1 泛型就像函数
1
2
3
4
5
|
const fn = (a, b) => a + b
const result = fn(1, 2) // 3
type F<A, B> = A | B
type Result = F<string, number> // string | number
|
函数的本质:推后执行的、部分待定的代码段
泛型的本质:推后执行的、部分待定的类型
2 为什么会有泛型
例如一个函数,接受的类型不确定(联合类型),从而返回值的类型也是不确定的,此时就可以使用泛型
使用switch区分参数类型,返回值类型也无法得到严格控制
没有泛型的类型系统,就如同没有函数的编程语言
3 实践
3.1 在泛型中使用extends
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// 要求:传入的泛型如果属于string就返回true,否则返回false
type R1 = LikeString<'hi'> // true
type R2 = LikeString<true> // false
// A extends B 相当于 A <= B, 读作“继承”或“包含于”
type LikeString<T> = T extends string ? true : false
// 再来一个例子
type R3 = LikePerson<{name: 'xxx', age: 10}> // true
type R4 = LikePerson<{gender: 'male'}> // false
type Person = {
name: string
age: number
}
type LikePerson<T> = T extends Person ? true : false
|
- 若
T
为never
,则表达式的值为never
(never是底类型,相当于0乘以任何数都为0)
1
2
3
|
type R = LikeString<never> // never
// 理论上来讲,never是最小的集合,是属于string的
// 但结果既不是true也不是false,而是never
|
- 若
T
为联合类型,则分开计算(相当于乘法分配律)
1
2
3
4
|
type ToArray<T> = T extends unknown ? T[] : never
type Result = ToArray<string | number> // string[] | number[]
// 使用
function f(a: T): ToArray<T> {}
|
3.2 在泛型中使用keyof
1
2
3
4
5
6
7
8
|
// 要求:返回传入类型的key值
type Person = {
name: string
age: number
}
// keyof: 返回一个对象全部key的集合
type GetKeys<T> = keyof T
type Result = GetKeys<Person> // 'name' | 'age'
|
3.3 在泛型中使用extends和keyof
1
2
3
4
5
6
7
8
|
// 要求:返回传入类型中对应key的类型
type Person = {
name: string
age: number
}
// 泛型约束:在参数列表中添加限制
type GetKeyType<T, K extends keyof T> = T[K]
type Result = GetKeyType<Person, 'name'> // stirng
|
3.4 映射类型in
1
2
3
4
5
|
type Person = {name: string; age: number}
type Copy<T> = {
[K in keyof T]: T[K]
}
type R = Copy<Person>
|
- 实现工具类Required、Partial、Readonly、Record
1
2
3
4
5
6
7
8
9
10
11
12
|
type Readonly2<T> = {
readonly [K in keyof T]: T[K]
}
type Partial2<T> = {
[K in keyof T]?: T[K]
}
type Required2<T> = {
[K in keyof T]-?: T[K]
}
type Record2<K extends number | string | symbol, V> = {
[key in K]: V
}
|
- 实现工具类Exclude、Extract、Pick、Omit
1
2
3
4
5
6
7
8
9
10
11
|
// 从A中排除B(差集)
type Exclude2<A , B> = A extends B ? never : A
type R4 = Exclude2<1 | 2 | 3, 1 | 2> // 3
// 提取公共的集合(交集)
type Extract2<A, B> = A extends B ? A : never
type R5 = Extract2<1 | 2 | 3, 2 | 4> // 2
// 选取类型中的某些属性
type Pick2<T, Key extends keyof T> = {
[K in Key]: T[K]
}
type R7 = Pick<Person, 'name' | 'age'> // {name: string, age: number}
|
1
2
3
4
5
6
7
8
|
// 思路一,利用Pick和Exclude
type Omit2<T, Key extends keyof T> = Pick<T, Exclude<keyof T, Key>>
// 思路二,正向思维,as断言
// 前半段key in keyof T是必须要写的 因为是映射类型的形式
// 后半段 key extends K ? never : key 用来排除K中的key
type Omit21<T, K> = {
[key in keyof T as key extends K ? never : key]: T[key]
}
|
3.5 总结
从类型中创造类型