TypeScript
1) 动态类型的问题
前面讲过 js 属于动态类型语言,例如
1 | function test(obj) { |
obj 可能只是个字符串
1 | test('hello, world') |
obj 也有可能是个函数
1 | test(()=>console.log('hello, world')) |
obj 类型不确定,就给后期使用者带来了麻烦,一旦参数传不对,代码就崩溃了
动态类型意味着
- 运行代码时才知道发生什么 (running the code to see what happens)
静态类型意味着
- 在代码运行前,就对它的行为做出预测 (make predications about what code is expected before it runs)
下面的 typescript 代码,就在代码运行前对参数加入了约束限制
1 | function test(msg : string) { |
- 限制了参数只能做 string 那些事
1 | function test(msg : Function) { |
- 限制了参数只能做函数那些事
2) 入门
安装 typescript 编译器
1 | npm install -g typescript |
编写 ts 代码
1 | function hello(msg: string) { |
执行 tsc 编译命令
1 | tsc xxx.ts |
编译生成 js 代码,编译后进行了类型擦除
1 | function hello(msg) { |
再来一个例子,用 interface 定义用户类型
1 | interface User { |
编译后
1 | function test(u) { |
可见,typescript 属于编译时实施类型检查(静态类型)的技术
3) 类型
类型 | 例 | 备注 |
---|---|---|
字符串类型 | string | |
数字类型 | number | |
布尔类型 | boolean | |
数组类型 | number[],string[], boolean[] 依此类推 | |
任意类型 | any | 相当于又回到了没有类型的时代 |
复杂类型 | type 与 interface | |
函数类型 | () => void | 对函数的参数和返回值进行说明 |
字面量类型 | “a”|”b”|”c” | 限制变量或参数的取值 |
nullish类型 | null 与 undefined | |
泛型 | <T> ,<T extends 父类型> |
标注位置
标注变量
1 | let message: string = 'hello,world' |
- 一般可以省略,因为可以根据后面的字面量推断出前面变量类型
1 | let message = 'hello,world' |
标注参数
1 | function greet(name: string) { |
很多时候,都能够推断出参数类型
1 | const names = ['Alice', 'Bob', 'Eve'] |
- 可以用类型推断,推断出 e 是 string 类型
标注返回值
1 | function add(a: number, b: number) : number { |
- 一般也可以省略,因为可以根据返回值做类型推断
复杂类型
type
1 | type Cat = { |
interface
1 | interface Cat { |
可选属性
如果需要某个属性可选,可以用下面的语法
1 | interface Cat { |
- 可选属性要注意处理 undefined 值
鸭子类型
1 | interface Cat { |
- const c1 并没有声明类型为 Cat,但它与 Cat 类型有一样的属性,也可以被当作是 Cat 类型
方法类型
1 | interface Api { |
字面量类型
1 | function printText(s: string, alignment: "left" | "right" | "center") { |
nullish 类型
1 | function test(x?: string | null) { |
- x?: string | null 表示可能是 undefined 或者是 string 或者是 null
泛型
下面的几个类型声明显然有一定的相似性
1 | interface RefString { |
可以改进为
1 | interface Ref<T> { |
- 泛型的要点就是
<类型参数>
,把【类型】也当作一个变化的要素,像参数一样传递过来,这样就可以派生出结构相似的新类型
函数定义也支持泛型
1 | function ref<T>(n: T): Ref<T> { |
4) 意义
更好理解框架
现在越来越多的前端框架采用 typescript,如果懂 typescript 语法,可以更好地阅读框架代码
以 Map 为例
1 | const map = new Map<string, string>() |
- 注意编译需要
tsc --target es6 .\xxx.ts
更好的提示
例如,从服务器返回的一段 json,如果不用 typescript,则编辑器也不能给出准确的提示
1 | interface User { |
5) 类
关于 TypeScript 与 JavaScript 中的类语法不是重点,class 相关语法只是起到辅助作用,更重要的是前面讲的 interface
基本语法
1 | class User { |
其实会被编译成这个样子(默认 –target=es3)
1 | var User = /** @class */ (function () { |
所以 js 中的 class,并不等价于 java 中的 class,它还是基于原型实现的,原理参考第二章(036、037)
只读属性
1 | class User { |
- readonly 是 typescript 特有的,表示该属性只读
方法
1 | class User { |
get,set
1 | class User { |
- 注意,需要在编译时加上
tsc --target es6 .\xxx.ts
选项 - es6 等价于 es2015,再此之上还有 es2016 … es2022
类与接口
1 | interface User { |
继承与接口
1 | interface Flyable { |
- Flyable & Animal 表示变量是 flyable 类型,同时也是 Animal 类型
方法重写
1 | class Father { |