Narrowing 类型收缩 - 《TypeScript学习笔记》

type guards (类型守卫) 和 narrowing

通过 if 条件语句对类型进行判断,TypeScript会对变量的类型进行分析,以明白这个分支下变量的具体类型,这个过程叫做 type guards 。而这整个由不确定类型到确定具体类型到过程就叫做 narrowing ,下面有几种方式可以对类型进行校验。

typeof 守卫

可以通过 typeofe 运算符对类型进行最基础对判断:

  • string
  • number
  • bigint
  • boolean
  • symbol
  • undefined
  • object
  • function

Truthiness narrowing(是否为真)

if 表达式内,JavaScript 对条件是否为真对判断并不是决定对,它会把非 boolean 类型对表达式转化为 boolean 类型进行判断。下面的值会被转化为 false

  • 0
  • NaN
  • ""(空字符串)
  • 0n (大整型0)
  • null
  • undefined

除了上面这些值会被转化为false,其它都会被转发为true

Equality narrowing(是否相等)

我们可以通过 ===!====!= 对类型进行收缩。比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function example(x: string | number, y: string | boolean) {
if (x === y) {
// We can now call any 'string' method on 'x' or 'y'.
x.toUpperCase();
// ^?
y.toLowerCase();
// ^?
} else {
console.log(x);
// ^?
console.log(y);
// ^?
}
}

instanceof narrowing(原型校验)

这种方式用来检查通过new对方式创建出来对对象对类型。

1
2
3
4
5
6
7
function logValue(x: Date | string) {
if (x instanceof Date) {
console.log(x.toUTCString());
} else {
console.log(x.toUpperCase());
}
}

赋值操作

TypeScript会根据赋值操作符=右边对类型决定变量的类型

1
let x = Math.random() < 0.5 ? 10 : "hello world!";

这里的 x 会被推断为 string | number 两种类型。

类型断言

对于自定义类型,可以通过 parameterName is Type 的方式断言某个变量是 Type 类型,其中 parameterName 必须为函数的参数

1
2
3
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}

联合类型

通过 | 符号来表示字面类型的组合,如:

1
2
3
4
5
interface Shape {
kind: "circle" | "square";
radius?: number;
sideLength?: number;
}

never 类型

never 类型表示一个不应该存在的状态,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
type Shape = Circle | Square;

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;
return _exhaustiveCheck;
}
}