一. 什么是泛型
- 泛型(Generic Types),generic就是多的意思,也就是表示多种类型
- 可以把泛型当作函数理解,泛型是接收其它类型的类型就好像函数是接收其它代码的代码
const f = (a: number, b: number) => a + b;
const result = f(1, 2); // 3
type F<A, B> = A | B;
type Result = F<string, number>; // string | number
// 这两者的区别就是圆括号变成了方括号,const 变成了type
- 函数的本质是什么?
- 有一种说法:函数的本质是推后执行的的代码
console.log(1);
const f1 = () => console.log(1);
f1();
- 另一种说法把一部分代码抠出来,用的时候再填入进去,也就是部分待定的代码
const f2 = (x: number) => console.log(x);
f2(2222);
const f3 = (fn: Function) => fn(1);
f3(console.log);
const f4 = (fn: Function, n: number) => fn(n);
f4(console.log, 4444);
二. 泛型的本质
- 上面我们已经说了函数的本质,那么既然我们说泛型和函数很像,那么我们不难得出,泛型的本质就是推后执行的,部分待定的类型
三. 为什么需要泛型
- 举个简单的例子
// 一个函数输入什么,输出就是什么,我们需要精确的确认返回的类型
// 我们不能单纯的认为输入是number | string | boolean,输出就是number | string | boolean,具体看图
function echo(whatever: number | string | boolean) {
return whatever;
}
- 总结:没有泛型有些奇怪的需求就无法满足。没有泛型的类型系统,就如同没有函数的编程语言
四. 难度为一星的泛型
- 直接通过带入法得到最后的类型
interface List<A> {
[index: number]: A;
}
type X1 = List<string>;
// x1是什么,通过带入法去理解,X1的结果等价于X2
interface X2 {
[index: number]: string;
}
type Y1 = List<string | number>;
interface Y2 {
[index: number]: string | number;
}
// 如何给类型参数一个默认值
interface Hash<V = string> {
[key: string]: V;
}
type H = Hash;
type H1 = Hash<String>;
type H2 = Hash<number | string>;
interface Person {
name: string;
}
type H3 = Hash<Person>;
五. 难度为二星的泛型
- extends关键字
type Person = { name: string };
// 这里的extends表示T这个集合在string里面或者和string重合,可以理解为包含于
type LikeString<T> = T extends string ? true : false;
type LikeNumber<T> = T extends number ? 1 : 2;
type LikePerson<T> = T extends Person ? 'yes' : 'no';
// 期望如果传入的类型跟string很像返回true
type R1 = LikeString<'hi'>; // true
type R2 = LikeString<true>; // false
type S1 = LikeNumber<6666>; // 1
type S2 = LikeNumber<false>; // 2
type T1 = LikePerson<{ name: 'Alice'; xxx: 1 }>; // yes
type T2 = LikePerson<{ xxx: 1 }>; // no
- 如果T是联合类型则会分开计算,有点像分配律
type ToArray<T> = T extends unknown ? T[] : never;
type Result = ToArray<string | number>;
// 这里的Result为string[] | number[]类型,可以根据以下步骤理解
// type Result = (string | number) extends unknown ? ...
// type Result = (string extends unknown ???? ...) | (number extends unknown ? ...)
// type Result = string[] | number[]
- 特殊规则,extends前面是never返回值就是never,有点像乘法里面的0
type ToArray<T> = T extends unknown ? T[] : String;
type Result = ToArray<never>; // 只要extends前面是never直接返回never
- 注意点: 以上两条规则只对泛型有效
type X = never extends unknown ? 1 : 2; // 1,这里没有用泛型,直接推
keyof关键字,获取对象类型的key的集合
type Person = { name: string; age: number };
type GetKeys<T> = keyof T;
type Result = GetKeys<Person>; // -- 'name' | 'age'
const r: Result = 'age';
- 取得对象类型中key的类型
type Person = { name: string; age: number };
// 泛型约束加类型取值
type GetKeyType<T, K extends keyof T> = T[K];
type Result1 = GetKeyType<Person, 'name'>; // string
type Result2 = GetKeyType<Person, 'age'>; // number
// 类型取值
type X = Person['name']; // string