思考:有没有发现自己学习了ts 还是看不懂别人的ts。奇奇怪怪的范型导致我们无法理解代码。为了能够轻松看懂别人ts代码,下面会总结出来源码中别人经常使用的范型。
1. typeof 的使用
获取数据的类型。
let p1 = {
name: "zhufeng",
age: 10,
gender: "male",
};
type Person =typeof p1
// 等价于
interface Person {
name: string;
age: number;
gender: string;
}
2. keyof 与 in 的使用
keyof 获取接口所有的key in 遍历所有的key 的使用 +? 变成可选符号,-?变成必选的符号
interface Person {
name: string;
age: number;
gender: "male" | "female";
}
//批量把一个接口中的属性都变成可选的
type PPersion = keyof Person; // "name" | "age" | "gender"
//也可以使用泛型,将key 编程可选的接口
type Part<T> = {
[key in keyof T]+?: T[key];
};
type Part1<T> = {
[key in keyof T]: T[key];
};
3. extends 条件类型的使用
Diff 寻找范型T中,在范型U中不存在的类型。
//never会被自动过滤
type Diff<T, U> = T extends U ? never : T;
type R = Diff<string | number | boolean, number>; // 返回的类型: string, boolean
type Filter<T, U> = T extends U ? T : never;
type R1 = Filter<string | number | boolean, number>; // 返回的类型: number
4. 内置条件类型
- TS 在内置了一些常用的条件类型,可以在 lib.es5.d.ts 中查看:
- utility-types
4.1 Exclude
- 从 T 可分配给的类型中排除 U
type Extract<T, U> = T extends U ? never: T;
type E = Exclude<string | number, string>; // number
4.2 Extract
从 T 可分配的类型中提取 U
type Extract<T, U> = T extends U ? T : never;
type E = Extract<string | number, string >; // string
4.3 NonNullable
type NonNullable<T> = T extends null | undefined ? never : T;
type E = NonNullable<string | number | null | undefined>; // string|number
5. infer 类型的使用
- 提取函数返回值类型
- 提取参数类型
- 提取构造函数类型
- 提取构造函数参数类型
type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any;
type Parameters<T> = T extends (...args: infer R) => any ? R : any;
type Constructor = new (...args: any[]) => any;
type ConstructorParameters<T extends Constructor> = T extends new (...args: infer P) => any ? P : never;
type InstanceType<T extends Constructor> = T extends new (...args: any[]) => infer R ? R : any;
function getUserInfo(name:string,age:number) {
return { name: "xxx", age: 10 };
}
class MyPerson {
constructor(name:string,age:number){}
}
// {
// name: string;
// age: number;
// }
type UserInfo = ReturnType<typeof getUserInfo>;
// [name: string, age: number]
type PParameters = Parameters<typeof getUserInfo>;
// [name: string, age: number]
type CConstructorParameters = ConstructorParameters<typeof MyPerson>;
type IInstanceType = InstanceType<typeof MyPerson>;
infer 的高级使用
type T1 = { name: string };
type T2 = { age: number };
type UnionToIntersection<T> = T extends { a: (x: infer U) => void; b: (x: infer U) => void } ? U : never;
type T3 = UnionToIntersection<{ a: (x: T1) => void; b: (x: T2) => void }>; // T1 & T2
6. 内置工具类型
6.1 Partial
Partial 可以将传入的属性由非可选变为可选。
type Partial<T> = { [P in keyof T]?: T[P] };
interface A {
a1: string;
a2: number;
a3: boolean;
}
type aPartial = Partial<A>;
const a: aPartial = {}; // 不会报错
类型递归
interface Company {
id: number
name: string
}
interface Person {
id: number
name: string
company: Company
}
type DeepPartial<T> = {
[U in keyof T]?: T[U] extends object
? DeepPartial<T[U]>
: T[U]
};
type R2 = DeepPartial<Person>
6.2 require
Required 可以将传入的属性中的可选项变为必选项
interface Person{
name:string;
age:number;
gender?:'male'|'female';
}
/**
* type Require<T> = { [P in keyof T]-?: T[P] };
*/
let p:Required<Person> = {
name:'zhufeng',
age:10,
//gender:'male'
}
6.3 Readonly
Readonly 通过为传入的属性每一项都加上 readonly 修饰符来实现
type Readonly<T> = { readonly [P in keyof T]: T[P] };
interface Person{
name:string;
age:number;
gender?:'male'|'female';
}
let p:Readonly<Person> = {
name:'zhufeng',
age:10,
gender:'male'
}
p.age = 11;
6.4 pick
Pick 能够帮助我们从传入的属性中摘取某一项返回
interface Animal {
name: string;
age: number;
gender: number;
}
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
type pig = Pick<Animal,'name'|'age'>;
// 等同于
// interface Pig {
// name: string;
// age: number;
// }
6.4 Record
type Record<K extends keyof any, T> = {
[P in K]: T;
};
7. 自定义高级类型
7.1 Omit
/**
* Omit (complements Pick)
* @desc From `T` remove a set of properties by key `K`
* @example
* type Props = { name: string; age: number; visible: boolean };
*
* Expect: { name: string; visible: boolean; }
* type Props = Omit<Props, 'age'>;
*/
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
7.2 Diff
/**
* Diff
* @desc From `T` remove properties that exist in `U`
* @example
* type Props = { name: string; age: number; visible: boolean };
* type DefaultProps = { age: number };
*
* // Expect: { name: string; visible: boolean; }
* type DiffProps = Diff<Props, DefaultProps>;
*/
type Diff<T extends object, U extends object> = Pick<
T,
Exclude<keyof T, keyof U>
>;
7.3 Intersection
/**
* Intersection
* @desc From `T` pick properties that exist in `U`
* @example
* type Props = { name: string; age: number; visible: boolean };
* type DefaultProps = { age: number };
*
* // Expect: { age: number; }
* type DuplicateProps = Intersection<Props, DefaultProps>;
*/
type Intersection<T extends object, U extends object> = Pick<
T,
Extract<keyof T, keyof U> & Extract<keyof U, keyof T>
>;
7.4 Overwrite
export type Overwrite<
T extends object,
U extends object,
I = Diff<T, U> & Intersection<U, T>
> = Pick<I, keyof I>;
// 案例:
type Props = { name: string; age: number; visible: boolean };
type NewProps = { age: string; other: string };
// Expect: { name: string; age: string; visible: boolean; }
type ReplacedProps = Overwrite<Props, NewProps>;
7.5 Merge
type O1 = {
id: number;
name: string;
};
type O2 = {
id: number;
age: number;
};
//Compute的作用是将交叉类型合并
type Compute<A extends any> = A extends Function ? A : { [K in keyof A]: A[K] };
type R1 = Compute<{ x: "x" } & { y: "y" }>;
type Merge<O1 extends object, O2 extends object> = Compute<
O1 & Omit<O2, keyof O1>
>;
type R2 = Merge<O1, O2>;
7.6 Compute
type Compute<A extends any> = A extends Function ? A : { [K in keyof A]: A[K] };