# Narrowing 缩小(类型细化)
将类型细化为比声明更具体的类型的过程称为缩小
# 通过typeof判断类型
通过typeof判断类型可以得出下列基本类型
- "string"
- "number"
- "bigint"
- "boolean"
- "symbol"
- "undefined"
- "object"
- "function"
typeof null === 'object',所以对null需要更细化的处理
# Truthiness narrowing
在if
条件语句中,0、NaN、"" (the empty string)、 0n (the bigint version of zero)、 null、 undefined
这些值都是false,其他都是true
多个条件处理null
function printAll(strs: string | string[] | null) {
if (strs !== null) {
if (typeof strs === "object") {
for (const s of strs) {
console.log(s);
}
} else if (typeof strs === "string") {
console.log(strs);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
实例二
interface Container {
value: number | null | undefined;
}
function multiplyValue(container: Container, factor: number) {
// Remove both 'null' and 'undefined' from the type.
if (container.value != null) {
console.log(container.value);
// Now we can safely multiply 'container.value'.
container.value *= factor;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# in
操作符缩写范围
type Fish = { swim: () => void };
type Bird = { fly: () => void };
function move(animal: Fish | Bird) {
if ("swim" in animal) {
return animal.swim();
}
return animal.fly();
}
type Fish = { swim: () => void };
type Bird = { fly: () => void };
type Human = { swim?: () => void, fly?: () => void };
function move(animal: Fish | Bird | Human) {
if ("swim" in animal) {
// (parameter) animal: Fish | Human
} else {
// (parameter) animal: Bird | Human
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# instanceof 操作符缩写范围
function logValue(x: Date | string) {
if (x instanceof Date) {
console.log(x.toUTCString());
// (parameter) x: Date
} else {
console.log(x.toUpperCase());
// (parameter) x: string
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 自动分配类型
let x = Math.random() < 0.5 ? 10 : "hello world!";
// let x: string | number
x = true; // Error
1
2
3
4
5
2
3
4
5
# 控制流分析
# 类型断言
要定义用户定义的类型防护,我们只需要定义一个返回类型为类型谓词的函数:
谓词的形式为parameterName is Type
,其中parameterName必须是当前函数签名中参数的名称。
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
1
2
3
4
2
3
4
有可能使用 isFish
来过滤类型是 Fish | Bird
的数组,并过滤出是Fish
的数组
const zoo: (Fish | Bird)[] = [getSmallPet(), getSmallPet(), getSmallPet()];
const underWater1: Fish[] = zoo.filter(isFish);
// or, equivalently
const underWater2: Fish[] = zoo.filter(isFish) as Fish[];
// The predicate may need repeating for more complex examples
const underWater3: Fish[] = zoo.filter((pet): pet is Fish => {
if (pet.name === "sharkey") return false;
return isFish(pet);
});
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 联合类型
interface Shape {
kind: "circle" | "square";
radius?: number;
sideLength?: number;
}
function handleShape(shape: Shape) {
// oops!
if (shape.kind === "rect") {
//自动检测出错误 This condition will always return 'false' since the types '"circle" | "square"' and '"rect"' have no overlap.
// ...
}
}
function getArea(shape: Shape) {
if (shape.kind === "circle") {
return Math.PI * shape.radius! ** 2;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
更好的实践
interface Circle {
kind: "circle";
radius: number;
}
interface Square {
kind: "square";
sideLength: number;
}
type Shape = Circle | Square;
function getArea(shape: Shape) {
if (shape.kind === "circle") {
return Math.PI * shape.radius ** 2;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface Circle {
kind: "circle";
radius: number;
}
interface Square {
kind: "square";
sideLength: number;
}
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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30