在了解工具泛型之前需要了解这几个概念
keyof
这里的keyof指的是 ts 里的概念。返回一个指定对象类型的键名组成联合类型
type User = {
name: string;
age: number;
};
type UserKey = keyof User; // 'name' | 'age'
若操作的是一个联合类型,且返回联合类型的公共 key。
type User = { name: string; age: number };
type Foo = { name: string; foo: string };
type Bar = { bar: string };
type A = keyof (User | Foo); // 'name'
type B = keyof (User | Bar); // never
若是想返回联合类型的所有 key,可如下
type UnionKeys<T> = T extends T ? keyof T : never;
type keys = UnionKeys<User | Foo | Bar>; // 'name' | 'age' | 'foo' | 'bar'
typeof
可以推断 javascript 对象的类型,返回更详细的对象类型。这里typeof指的是ts里的概念
const user = { name: "singing", age: 20 };
type UserType = typeof user; // { name: string; age: number }
type UserKey = keyof typeof user; // "name" | "age"
extends
- 条件判断
A extends B: 若是A的每一个类型都可以赋值给B,则为true,反之为false。 可以这么理解,表达式为true时,说明当一个类型是A类型时,则一定可以是B类型。但反过来,如果一个类型是B类型,不一定是A类型。也即A应该是子类,B是父类(子类的限制比父类的多,所以,当其满足子类的限制时,一定满足父类的限制)。如 Animal 和 Dog。当一个 xiaohuang 是 Dog 类型时,一定是 Animal。
type User = {
name: string;
age: number;
};
type Student = {
name: string;
age: number;
grade: number;
};
type T = Student extends User ? string : number; // string
type P = User extends Student ? string : number; // number
-
泛型使用
- 分配条件类型
When conditional types act on a generic type, they become distributive when given a union type
当第一个参数为泛型类型。当传入的第一个参数为联合类型时,则使用分配律计算最终的结果。
分配律:将联合类型的联合项拆成单项,分别代入条件类型,然后将每个单项代入得到的结果再联合起来,得到最终的判断结果。
type A = 'x' | 'y' | 'z' type B = 'x' | 'k' type P<T, K> = T extends K ? string : number; type C = P<A, B>; // string | number type D = A extends B ? string : number; // numbernever的特殊处理。当传入的T参数为never,代表一个空的联合类型。也即没有使用分配律,P的表达式并没有执行,返回的依然是nevertype E = P<never, A>; // never type F = never extends A ? string : number; // string;防止条件判断中的分配
可以使用
[]将泛型参数包含起来,即不会使用分配律,而是将参数作为一个整体去判断type P1<T, K> = [T] extends [K] ? string : number; type G = P1<B, A>; // string type H = P1<A, B>; // number- 约束参数
type P2<T, K extends keyof T> = { [P in K]: string };这里约束了
P2的第二个参数必须是第一个参数的 key
工具泛型
Exclude
参数应当是联合类型
type Exclude<T, K> = T extends K ? never : T;
Extract
参数应当是联合类型
type Extract<T, U> = T extends U ? T : never;
Pick
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
Omit
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;