TypeScript收窄

简单来说就是类型过滤,能够缩窄类型的范围

typeof

可以通过typeof返回的类型缩小范围,需要注意的是typeofnull 返回的是字符串object,ts在判断时会报错提示
通过Boolean()可以返回一个type为boolean,value为true的类型
通过!!world可以返回一个type为true,value为true的类型(一个狭窄的文字布尔类型 true)

平等缩小

指的是通过===!====!=判断类型是否相同,,可以配合联合类型使用
例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function example(x: string | number, y: string | boolean) {
if (x === y) {
// We can now call any 'string' method on 'x' or 'y'.
x.toUpperCase();

(method) String.toUpperCase(): string
y.toLowerCase();

(method) String.toLowerCase(): string
} else {
console.log(x);

(parameter) x: string | number
console.log(y);

(parameter) y: string | boolean
}
}

通过in收窄

通常搭配联合类型使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Fish = { swim: () => void };
type Bird = { fly: () => void };
type Human = { swim?: () => void; fly?: () => void };

function move(animal: Fish | Bird | Human) {
if ("swim" in animal) {
animal;

// (parameter) animal: Fish | Human
} else {
animal;

// (parameter) animal: Bird | Human
}
}

instanceof

通过判断实例是否再原型上来收窄类型范围

1
2
3
4
5
6
7
8
9
10
11
function logValue(x: Date | string) {
if (x instanceof Date) {
console.log(x.toUTCString());

// (parameter) x: Date
} else {
console.log(x.toUpperCase());

// (parameter) x: string
}
}

Assignments

ts能根据右侧的赋值适当的收窄左侧

1
2
3
4
5
6
7
8
let x = Math.random() < 0.5 ? 10 : "hello world!";

// let x: string | number
x = 1;

console.log(x);

// let x: number

这些分配中的每一个都是有效的,这是因为一开始x被赋值了number或string类型

控制语句

基于可达性的代码分析称为控制流分析。TypeScript 在遇到类型保护和赋值时使用这种流分析来缩小类型。当分析一个变量时,控制流可以一次又一次地分裂和重新合并,并且可以观察到该变量在每个点具有不同的类型

使用类型谓词

定义一个返回类型为类型谓词的函数
谓词采用 形式 parameterName is Type 其中parameterName必须是当前函数签名中的参数名称
感觉上像是自定义了一个用于收窄类型的函数返回值类型

举例说明

1
2
3
4
5
6
7
8
9
10
11
12
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}

// Both calls to 'swim' and 'fly' are now okay.
let pet = getSmallPet();

if (isFish(pet)) {
pet.swim();
} else {
pet.fly();
}

Discriminated unions

为了让ts能够更准确的检查,当我们通过一些属性去判断参数的类型时,编译器往往无法正确判断属性是否存在。虽然我们可以通过类型断言和非空声明解决,但应该有更好的办法。

我们需要将我们所知道的信息传达给类型检查器,可以更详细的声明类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface Circle {
kind: "circle";
radius: number;
}

interface Square {
kind: "square";
sideLength: number;
}

type Shape = Circle | Square;

function getArea(shape: Shape) {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;

// (parameter) shape: Circle
case "square":
return shape.sideLength ** 2;

// (parameter) shape: Square
}
}

never 类型

缩小范围时,可以将联合的选项减少到已消除所有可能性并且一无所有的程度。在这些情况下,TypeScript 将使用一种never类型来表示不应该存在的状态。

穷举检查

never类型可以分配给任何类型,但是没有类型能够分配给never(never本身除外)。所以我们可以通过在switch语句中的default下通过赋值never来检查条件是否都考虑充分,ts会帮我们自动进行穷举检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
interface Triangle {
kind: "triangle";
sideLength: number;
}

type Shape = Circle | Square | Triangle;

function getArea(shape: Shape) {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.sideLength ** 2;
default:
const _exhaustiveCheck: never = shape;
// Type 'Triangle' is not assignable to type 'never'.
return _exhaustiveCheck;
}
}
作者

徐云飞

发布于

2022-09-12

更新于

2023-02-05

许可协议

评论