泛型编程(上)
泛型就像函数
函数
1 | const f = (a, b) => a + b |
泛型
1 | type F<A, B> = A | B |

函数的本质是什么
函数的本质是推后执行的、部分待定的代码
1 | // 立即执行 |
泛型的本质是什么
泛型的本质是推后执行的、部分待定的类型
没有泛型的类型系统,就如同没有函数的编程语言
什么时候需要泛型
当我们需要准确的定义返回值的类型的时候,就需要泛型

这时候你可能会说,做类型收窄不就行了吗?就像下面这样
1 | function echo(whatever: number | string | boolean) { |
但是你会发现,这样写得到的返回值类型是不准确的
1 | const a = echo(233); |
这时候,泛型就派上用场了
1 | function echo<T>(whatever: T): T { |
简单泛型示例
1 | type Union<A, B> = A | B; |
条件类型(Conditional Types)

T extends string
可理解为 T <= string
(T
包含于 string
)
1 | type R1 = LikeString<'hi'> // true |
泛型中的特殊运算规则
现有如下泛型 ToArray
1 | type ToArray<T> = T extends unknown ? T[] : never; |
问:type Result = ToArray<string | number>
的类型是什么?
直接说答案:Result
为 string[] | number[]
你可能会疑惑,按照一般的理解,string | number
是包含于 unknown
的,那么 Result
就应该是 (string | number)[]
呀
按照通常的理解是没错,但因为这是在泛型中,因此规则会有些许不同
可以按照如下拆分过程来进行理解记忆:
1 | type Result = ToArray<string | number>; |
即泛型中的联合类型会分开进行运算,这就好像是乘法中的分配率 (A + B) X C = A X C + B X C
再问:type Result2 = ToArray<never>
的类型是什么?
答案是 never
同样按照一般的理解,通常情况下(非泛型中),never
是包含于 unknown
的,那么 Result
应该是 never[]
才对
但 Result
在此处却为 never
1 | type Result = ToArray<never>; // never |
即泛型中的 never
进行任何运算都只会得到 never
,这就好像是乘法中的零 0 X C = 0
注意:以上讨论的规则只对泛型有效
在泛型中使用 keyof
keyof
能获取对象的所有 key
,并将获取到的 key
做一个联合(并集)
1 | type Person = { name: string; age: number }; |
常和映射类型一起使用
1 | type Readonly<T> = { |
在泛型中使用 extends keyof
1 | type Person = { name: string; age: number }; |
K extends keyof T
的写法称为泛型约束,GetKeyType
第二个参数 k
的类型必须包含于 string | number