其他
TypeScript 规定,变量只有赋值后才能使用,否则就会报错
1
2let x:number;
console.log(x) // 报错上面示例中,变量
x
没有赋值就被读取,导致报错。而 JavaScript 允许这种行为,不会报错,没有赋值的变量会返回undefined
类型声明并不是必需的
如果没有声明,TypeScript 会自己推断类型
1 | let foo = 123; |
TypeScript 也可以推断函数的返回值,正因如此,函数返回值的类型通常是省略不写的
1 | function toString(num:number) { |
三种特殊类型
- any:
- 定义:任意类型,对此 TS 会关闭类型检查
- 注意:any 类型不一定等于没写类型,因为没写时 TS 有可能自己推导出类型。
- 缺点:any 类型存在污染变量,慎用
1
2
3
4
5let x:any = 'hello';
let y:number;
y = x; // 不报错
y*123 // y 值其实是字符串了,但不报错 - 适用场景:重构老项目时可用,其他场景少用
- unknown:
- 定义:与 any 类似,所有类型的值都可以赋值给 unknown,但可解决 any 的污染变量问题
1
2
3
4
5let x:unknown;
x = true; // 正确
x = 42; // 正确
x = 'Hello World'; // 正确 - 注意:unknown 无法赋值给 any/unknown 以外类型,以此解决了 any 的污染变量问题
1
2
3
4let v:unknown = 123;
let v1:boolean = v; // 报错
let v2:number = v; // 报错 - 注意:直接调用 unknown 的属性和方法都是不允许的,除非经过类型缩小
1
2
3
4
5
6
7
8
9
10let v1:unknown = { foo: 123 };
v1.foo // 报错
let v2:unknown = 'hello';
v2.trim() // 报错
let s:unknown = 'hello';
if (typeof s === 'string') {
s.length; // 正确
} - 适用场景:凡是需要设为 any 类型的地方,通常都应该优先考虑设为 unknown 类型
- 定义:与 any 类似,所有类型的值都可以赋值给 unknown,但可解决 any 的污染变量问题
- never
- 定义:空类型。即不可能有值。
- 注意:对应集合论中的空集,never 类型是所有类型的子集,因此可赋给所有类型
- 适用场景:不可能返回值的函数,或永久执行的函数,返回值的类型就可以写为 never,never 不是 void,前者表示函数没有执行结束,不可能有返回值;后者表示函数正常执行结束,但是不返回值
1
2
3
4
5
6
7
8
9
10
11
12
13function f():never {
throw new Error('Error');
}
function g():never {
while(true) {
console.log('forever')
}
}
let v1:number = f(); // 不报错
let v2:string = f(); // 不报错
let v3:boolean = f(); // 不报错
类型系统
JS 中的 8 种类型(不是 TS)
- boolean
- string
- number
- bigint
- symbol
- object
- undefined
- null
注意,所有类型的名称都是小写字母,首字母大写的Number
、String
、Boolean
等在 JavaScript 语言中都是内置对象,而不是类型名称
在 JS 中,typeof
运算符只可能返回八种结果,与上面的类型不同。注意 null
的类型是 object
,以及多了一个 function
类型
1 | typeof undefined; // "undefined" |
而在 TS 中,typeof 返回的是该值的 TS 类型
1 | const a = { x: 0 }; |
同一段代码可能存在两种typeof
运算符,一种用在值相关的 JavaScript 代码部分,另一种用在类型相关的 TypeScript 代码部分
1 | let a = 1; |
上面示例中,用到了两个typeof
,第一个是类型运算,第二个是值运算。它们是不一样的,不要混淆。
JavaScript 的 typeof 遵守 JavaScript 规则,TypeScript 的 typeof 遵守 TypeScript 规则。它们的一个重要区别在于,编译后,前者会保留,后者会被全部删除。
上例的代码编译结果如下。
1 | let a = 1; |
上面示例中,只保留了原始代码的第二个 typeof,删除了第一个 typeof
undefined 与 null
另外,undefined
和 null
既可以作为值,也可以作为类型,取决于在哪里使用它们
undefined
类型可包含一种值undefined
(不像boolean
,包含 true 和 false)。前者是类型,后者是值,需要区分
1 | let x:undefined = undefined; |
- null 类型可包含一种值
null
。前者是类型,后者是值,需要区分
1 | const x:null = null; |
- 类型未声明,值为
undefined
或null
,它们的类型会被推断为any
1 | let a = undefined; // any |
- 声明为
null
类型,但未赋值,默认值为undefined`
而不是null
1
2let x:null;
console.log(x) // 输出 undefined 而不是 null
Object 与 object
Object
广义对象,少用。除了undefined
和null
这两个值不能转为对象,其他任何值都可以赋值给Object
类型。
1 | let obj:Object; |
另外,空对象{}
是Object
类型的简写形式,所以使用Object
时常常用空对象代替
1 | let obj:{}; // 等价于 let obj:Object; |
上面示例中,变量obj
的类型是空对象{}
,就代表Object
类型。
显然,无所不包的Object
类型既不符合直觉,也不方便使用。
object 类型
狭义对象,常用。只包含对象、数组和函数,不包括原始类型的值。大多数时候,我们使用的是 object
而不是 Object
1 | let obj:object; |
值类型与联合类型
1 | // x 的类型是 "https" |
变量x
是const
命令声明的,TypeScript 就会推断它的类型是值https
,而不是string
类型。
值类型一般不会单独使用,而是结合联合类型,表示值的枚举
1 | let setting:true|false; |
上面的示例都是由值类型组成的联合类型,非常清晰地表达了变量的取值范围。其中,true|false
其实就是布尔类型boolean
联合类型除了和值类型一起使用,也可用于多种类型
1 | let name:string|number; |
“类型缩小”是 TypeScript 处理联合类型的标准方法,凡是遇到可能为多种类型的场合,都需要先缩小类型,再进行处理。实际上,联合类型本身可以看成是一种“类型放大”(type widening),处理时就需要“类型缩小”(type narrowing)
1 | function printId( |
或
1 | function getPort( |
type 命令
type
命令用来定义一个类型的别名
1 | type Age = number; |
type 不允许重名
1 | type Color = 'red'; |
数组
JavaScript 数组在 TypeScript 里面分成两种类型,分别是数组(array)和元组(tuple)
数组的 TS 声明
TypeScript 数组有一个根本特征:所有成员的类型必须相同
1 | let arr:number[] = [1, 2, 3]; // 普通写法,推荐 |
数组的 TS 类型推断
如果变量的初始值是空数组,那么 TypeScript 会推断数组类型是any[]
。
1 | // 推断为 any[] |
后面,为这个数组赋值时,TypeScript 会自动更新类型推断。
1 | const arr = []; |
如果初始值不是空数组,类型推断就不会更新。
1 | // 推断类型为 number[] |
多维数组
TypeScript 使用T[][]
的形式,表示二维数组,T
是最底层数组成员的类型。
1 | var multi:number[][] = |
元组
元组和数组最大的区别就是,元组的各个成员的类型可以不同。因此它必须明确声明每个成员的类型
1 | const s:[string, string, boolean] = ['a', 'b', true]; |
元组成员的类型可以添加问号后缀(?
),表示该成员是可选的,但必须处于必选成员之后
1 | type myTuple = [ |
由于类型声明是必须的,所以大多数情况元组的元素个数是确定的,但也有例外
1 | type t1 = [string, number, ...boolean[]]; |