keyof 和 in
对于任何类型 T, keyof T 的结果为该类型上所用共有属性key的联合类型:
interface Point {
x: number
y: number
}
// P = 'x' | 'y'
type P = keyof Point
现在我们编写来一个函数获取任意对象的属性值,一开始我们可能会这样写:
const foo = {
hello: 'world'
}
function getValue(obj: Object, key: string) {
return obj[key]
}
但是这样写会报错:
这时我们可以使用 keyof 来加强该函数的功能:
function getValue<T extends object, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
in 可以迭代联合类型中的所有项:
type Foo = 'x' | 'y'
type Bar = { [P in Foo]: number }
// 相当于
// type Bar = {
// x: number;
// y: number;
// }
条件类型
类似于js里的三目运算符:
// type A = true
type A = 'x' extends 'x' ? true : false
// type B = 2
type B = 'x' | 'y' extends 'x' ? 1 : 2
// type D = 1 | 2
type C<T> = T extends 'x' ? 1 : 2
type D = C<'x' | 'y'>
// type F = 2
type E<T> = [T] extends 'x' ? 1 : 2
type F = E<'x' | 'y'>
这里需要注意的是:
-
如果用于简单的条件判断,则是直接判断前面的类型是不是
extends后面的类型。 -
如果前面的类型是泛型,并且是联合类型,则联合类型会被分解为一个个子类型,分别判断是否
extends后面的类型。 -
想要阻止分类,使用元组类型包裹即可
[T]。
infer
使用 infer 可以在 extends 条件类型中动态推断当前的类型,例子如下:
type Foo<T> = T extends { a: (x: infer K) => infer U } ? K | U : never
// type Bar = string | number
type Bar = Foo<{ a: (x: number) => string }>
Partial、Required 和 Readonly
Partial<T>将T的所有属性变成可选的:
type Partial<T> = {
[P in keyof T]?: T[P]
}
[P in keyof T]遍历T上的所有属性?:让属性变为可选的T[P]取得原来的属性值
Required<T>将T的所有属性变成必选的:
type Required<T> = {
[P in keyof T]-?: T[P]
}
Readonly<T>将T的所有属性变成只读的:
type Readonly<T> = {
readonly [P in keyof T]: T[P]
}
Pick 和 Record
Pick<T, K> 从 T 中挑选一组属性 K 并组成一个新的类型:
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
// type Foo = { a: number }
type Foo = Pick<{a: number, b: number}, 'a'>
Record<K, T> 构造一个新的类型,key 为联合类型 T 中的每个子类型,类型为 K:
// keyof any 的结果是 string | number | symbol,因为 key 只能是这三种类型
type Record<K extends keyof any, T> {
[P in K]: T
}
// type Foo = { a: stirng; b: string }
type Foo = Record<'a' | 'b', string>
// type Bar = { [key: string]: string }
type Bar = Record<string, string>
Exclude、Extract 和 Omit
Exclude<T, U> 提取存在于T,但不存在于U的类型组成新的类型:
type Exclude<T, U> = T extends U ? never : T
// type Foo = 'b'
type Foo = Exclude<'a' | 'b', 'a' | 'c'>
Extract<T, U> 取交集:
type Extract<T, U> = T extends U ? T : never
// type Foo = 'a'
type Foo = Exclude<'a' | 'b', 'a' | 'c'>
Omit<T, K> 从类型 T 中忽略 K 中的所有属性:
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>
interface User {
age: number
name: string
}
// type Foo = interface User { name: string }
type Foo = Omit<User, 'age'>
Parameters 和 ReturnType
Parameters 获取函数的参数类型,并把他们放到一个元组中。
type Parameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never
// type Foo = [a: number, b: number]
type Foo = Parameters<(a: number, b: number) => void>
Parameters 获取函数的返回值。
type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any
// type Foo = string
type Foo = Parameters<(a: number, b: number) => string>