探索 TypeScript 类型注解 - 高级类型
Exploring TypeScript Type Annotations - Advance Types
作者: zhilidali
欢迎来到 《探索 TypeScript 类型注解》 系列教程。
上一篇介绍了类型检查机制,本篇深入探索高级类型。
目录
交叉类型
交叉类型将多个类型合为一个类型: T & U
interface TypeA { a: number }
interface TypeB { b: number }
let a: TypeA = { a: 1 };
let b: TypeB = { b: 2 };
let c: TypeA & TypeB = { ...a, ...b };
联合类型
联合类型表示一个值可以是几种类型之一: T | U
具有联合类型的值只能访问类型的共有成员。
// Union Type
let tsUnion: number | string = 1;
tsUnion.length; // error: 只能访问共有成员
索引类型
索引类型查询操作符
keyof T
:表示为 T 的公有属性名的联合。
interface F { a: string; b: number; }
type foo = keyof F;
// type foo = 'a' | 'b'
索引访问操作符
T[K]
:表示 T
的属性 K
的类型。
interface F { a: string; b: number; }
type foo = F['a'];
// type foo = string
索引类型 && 索引签名
如果类型 T
带有字符串索引签名,那么 keyof T
为 string | number
类型。
如果类型 T
带有数字索引签名,那么 keyof T
为 number
类型。
如果类型 T
带有索引签名,那么 T[K]
为索引签名的类型。
interface B { [index: string]: string; }
type foo = keyof B;
// type foo = string | number
type bar = B['string'];
// type bar = string
映射类型
映射类型可以基于旧类型创建新类型。
[K in T]: Type
:类型变量 K
会把字符串字面量联合类型 T
的每个字符串都映射为属性。
type Foo = 'a' | 'b';
type Bar = {
[K in Foo]: number;
}
// 等同于:
// type Bar = {
// a: number;
// b: number;
// }
在映射类型中,新类型可以相同的形式转换旧类型中的每个属性,例如,例如,可以将类型的所有属性设置为可选或只读。
由于转换为只读或可选等功能非常有用,它们被包含在 TypeScript 的标准库中, 详情见下篇实用工具类型。
interface Foo {
a: number;
b: number;
}
type FooPartial = {
[P in keyof Foo]?: Foo[P];
}
// 等同于:
// type FooPartial = {
// a?: number | undefined;
// b?: number | undefined;
// }
type FooReadonly = {
readonly [P in keyof Foo]: Foo[P];
}
// 等同于:
// type FooReadonly = {
// readonly a: number;
// readonly b: number;
// }
条件类型
T extends U ? X : Y
: 如果 T
可以赋值给 U
,那么类型是 X
,否则为 Y
type TypeName<T> = T extends string ? "string" : "number";
type Foo = TypeName<'ts'>;
// type Foo = "string"
type Bar = TypeName<number>;
// type Bar = "number"
嵌套条件类型
type TypeName<T> =
T extends string ? 'string' :
T extends number ? 'number' :
T extends boolean ? 'boolean' :
T extends undefined ? 'undefined' :
T extends Function ? 'function' :
'object';
type Foo = TypeName<string>;
// type Foo = "string"
type Bar = TypeName<true>;
// type Bar = "boolean"
分布式条件类型
如参数 T
为 A | B
,条件类型会自动解析为 (A extends U ? X : Y) | (B extends U ? X : Y)
type Baz = TypeName<1 | false>
// type Baz = "number" | "boolean"
条件类型中的类型推断
在 extends
子句中,允许使用 infer
声明一个 类型变量,可以在 true 分支中被引用
type A<T> = T extends { a: infer U } ? U : any;
type Foo = A<{ a: number }>
// type Foo = number
type Bar = A<number>
// type Bar = any
声明多个同名 类型变量 会被推断为联合类型
type A<T> = T extends { a: infer U, b: infer U } ? U : any;
type Foo = A<{ a: number, b: string }>
// type Foo = string | number
结语
本篇介绍了类型的高级类型,下篇将探索 TypeScript 提供的实用工具类型。
协议
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。