类型推导

前面我们简单介绍了下 TS 中的基本类型,但是对于初次使用 TS 的用户来说明显感觉比 JS 繁琐很多(JS 中变量不需要指定类型),难道以后每声明一个变量都需要标明类型吗?

在 TypeScript 中,不是每个地方都需要标注类型,因为类型推断允许您无需编写额外的代码即可获得大量功能。

当声明一个变量没有赋值的时候默认是 any 类型

  1. const a; // any

默认在初始化的时候会进行类型推导

  1. let str = 'name'; // str为string类型
  2. str = 1; // Type 'number' is not assignable to type 'string'.

包装对象

在使用基本数据类型时,会将原始类型包装成对象类型

  1. // 11..toString() -> Number(11).toString()
  2. const number1:number = 11
  3. // Number(11) 返回的是一个基本数据类型值
  4. const number2:number = Number(11)
  5. // 下面这样不行,不能把实例赋值给基本类型
  6. // semantic error TS2322: Type 'Number' is not assignable to type 'number'.
  7. 'number' is a primitive, but 'Number' is a wrapper object. Prefer using 'number' when possible.
  8. // const number3:number = new Number(11)
  9. // 类也是一个类型,它可以描述实例
  10. const number4:Number = new Number(11)
  11. const number5:Number = 11

联合类型

联合类型表示赋的值是多个类型中的一个,用 | 分割每个类型。如:

  1. let a: number | string;
  2. a = 1;
  3. a = '';

变量 a 可以赋值为 number或者 string 类型,除此之外不能将其它类型的值赋值给它。如下代码会报错:

  1. // Type 'boolean' is not assignable to type 'string | number'.
  2. a = false;

在使用联合类型时,没有赋值时只能访问联合类型中共有的方法和属性:

  1. let name:string | number // 联合类型
  2. console.log(name!.toString()); // 公共方法
  3. // 报错:Property 'toFixed' does not exist on type 'string | number'.Property 'toFixed' does not exist on type 'string'.
  4. console.log(name!.toFixed(2)); // number方法
  5. // 报错:bProperty 'toLowerCase' does not exist on type 'string | number'.Property 'toLowerCase' does not exist on type 'number'.
  6. console.log(name!.toLowerCase()); // 字符串方法
  7. // 如果我们想调用它们特定的方法,需要先给它们赋值,也就是指明这个变量到底是什么类型
  8. name = 10;
  9. console.log(name!.toFixed(2)); // number方法
  10. name = 'zf';
  11. console.log(name!.toLowerCase()); // 字符串方法

上述代码中的 ! 表示值非空,也就是一定有值的意思。

类型断言

类型断言可以用来手动指定一个值的类型。类型断言有两种形式,一种是使用 as 语法,一种是使用尖括号,但是使用尖括号的写法和JSX 语法有冲突,所以不建议使用这个写法。

  1. const ele:HTMLElement | null = document.getElementById('#app')
  2. ele!.style.color = 'red';
  3. (ele as HTMLElement).style.color = 'red';
  4. // 将ele强转成HTMLElement,这样写和JSX语法有冲突,尽量不要这么写
  5. (<HTMLElement>ele).style.color = 'red';
  6. // 双重断言,不建议使用,因为会破坏原有类型
  7. (ele as unknown) as boolean
  8. let name: string | number;
  9. // semantic error TS2454: Variable 'name' is used before being assigned.
  10. // (name as number).toFixed();
  11. (name! as number).toFixed();
  12. // 这里赋的初始值是 number 类型,下面调用的的是字符串的方法
  13. let age: string | number = 1;
  14. // semantic error TS2352: Conversion of type 'number' to type 'string' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  15. // (age as string).toLowerCase();
  16. // 双重断言
  17. (age as unknown as string).toLowerCase()

字面量类型

可以用字面量当做类型,给变量赋值时也只能采用这几个值(限定值),类似枚举。

  1. let direction:'up'|'down'|'left'|'right'
  2. direction = 'up'
  3. // Type '"aaa"' is not assignable to type '"up" | "down" | "left" | "right"'
  4. // direction = 'aaa'

如果我们还有变量 direction2、direction3…,每一个都像声明 direction 一样写未免有些麻烦,这个时候我们可以使用 type 来给类型起个别名,方便后续使用。

  1. // 类型字面量
  2. type Direction = 'up'|'down'|'left'|'right'
  3. let direction2: Direction
  4. direction2 = 'left'

联合类型

联合类型描述的值可以是几种类型之一,使用竖线 | 来分隔每个类型。举个🌰:

  1. let a:string|number;

a 的值既可以是字符串也可以是数组。

下面这个方法,当传入的是字符串则按姓名排序,如果传入的是数字则按学号排序

  1. function sortByType(type:string|number) {
  2. if (typeof type == 'string') {
  3. console.log('按姓名排序', type);
  4. }else {
  5. console.log('按学号排序', type);
  6. }
  7. }
  8. sortByType(1)

联合类型和字面量类型的区别:

  1. type Direction = 'up' | 'down';
  2. type Info = string | number | boolean;
  3. const direction: Direction = 'up';
  4. const info1: Info = '1';
  5. const info2: Info = '2';
  6. const info3: Info = '3';

从上面的例子可以看出,字面量类型声明的变量可赋值的范围就那么指定的那么几个;使用联合类型声明的变量可赋值的种类更多。