在学习ts源码的时候,发现很多泛型还是看不懂,于是想写一篇文章,总结一下常用的泛型。
// 联合类型
interface Bird {
name: string;
fly(): void;
}
interface Person {
name: string;
talk(): void;
}
type BirdPerson = Bird | Person;
let p: BirdPerson = { name: "zfeng", fly() {} };
let p1: BirdPerson = { name: "zfeng", talk() {} };
联合类型使用 “|”表示 的关系, 满足其中的一个情况即可。
interface Bird {
name: string;
fly(): void;
}
interface Person {
name: string;
talk(): void;
}
type BirdPerson = Bird & Person;
let p: BirdPerson = { name: "zhufeng", fly() {}, talk() {} };
交叉类型使用“&”,表示与的关系,需要满足所有的情况。
type Extract<T, U> = T extends U ? T : never;
type Exclude<T, U> = T extends U ? never : T;
type NonNullable<T> = T extends null | undefined ? never : T;
type N = NonNullable<string | number | null | undefined>;// 删除null和undifined;
type E = Exclude<string | number, string>; // 排除关系 输出 string;
type I = Extract<string | number, string>; // 包含关系 输出 number;
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
function getUserInfo(name: string, age: number) {
return { name, age };
}
type UserInfo = ReturnType<typeof getUserInfo>;
const userA: UserInfo = {
name: "zhufeng",
age: 10,
};
type Parameters<T> = T extends (...args: infer R) => any ? R : any;
function getUserInfo(name: string, age: number) {
return { name, age };
}
type T1 = Parameters<typeof getUserInfo>; // [name: string, age: number]
很多人对于泛型的理解还停留在基础的层面,我讲站在集合的视角去理解一下什么叫泛型。
给定一个接口 Persion, 里面有name,age,visiable,三个字段,现在的要求是 得到一个新的接口,里面只有name,age。一般人常见的思路
interface Person {
name: string;
age: number;
visiable: boolean;
}
interface Person1 {
name: string;
age: number;
}
我们从写一个接口,就可以达到要求。但是这样子的写法,显得十分冗余。其实ts提供了方法,让我们可以实现,让我们一起看一下的例子。
// pick 的原理
// type Pick<T, K extends keyof T> = { [P in K]: T[P] };
interface Person {
name: string;
age: number;
visiable: boolean;
}
type Person1 = Pick<Person, 'name'|'age'> ;
Person1 就包含 name,age 字段。
interface Person {
name: string;
age: number;
visiable: boolean;
}
type Exclude<T, U> = T extends U ? never : T;
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
type Person2 = Omit<Person, "age">;
我们把一个接口当作一个集合,那么两个集合的操作主要有 并集,交集,差集。
type Extract<T, U> = T extends U ? T : never;
type Intersection<T extends object, U extends object> = Pick<
T,
Extract<keyof T, keyof U> & Extract<keyof U, keyof T>
>;
type C1 = { name: string; age: number; visible: boolean };
type C2 = { name: string; age: number; sex: number };
type C3 = Intersection<C1, C2>;
交集的定义 对于给定的两个集合,返回一个包含两个集合中共有元素的新集合。通过Intersection实现交集,可以获得一个新接口,C3只包含 name.age。如上图。
type Exclude<T, U> = T extends U ? never : T;
type Diff<T extends object, U extends object> = Pick<
T,
Exclude<keyof T, keyof U>
>;
type C1 = { name: string; age: number; visible: boolean };
type C2 = { name: string; age: number; sex: number };
type C11 = Diff<C1, C2>;
差集的定义 对于给定的两个集合,返回一个包含所有存在于第一个集合且不存在于第二个集合的元素的新集合。通过Diff实现差集,可以获得一个新接口,接口只有visiable。如上图。
并集的定义 对于给定的两个集合,返回一个包含两个集合中所有元素的新集合。通过Merge实现并集,可以获得一个新接口,接口包含C1,C2 的所有属性。如上图。
//Compute的作用是将交叉类型合并
type Compute<A extends any> = A extends Function ? A : { [K in keyof A]: A[K] };
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
type Merge<O1 extends object, O2 extends object> = Compute< O1 & Omit<O2, keyof O1>>;
type C1C2 = Merge<C1, C2>;
type C1 = { name: string; age: number; visible: boolean };
type C2 = { name: string; age: string; sex: number };
C1,C2做merge, C1中有age,类型为number,C2中有age,类型为string,那么合并之后,age是string,还是number类型呢?
Overwrite 泛型,解决了谁覆盖谁的问题。
type C1 = { name: string; age: number; visible: boolean };
type C2 = { name: string; age: string; sex: number };
type Overwrite<
T extends object,
U extends object,
I = Diff<T, U> & Intersection<U, T>
> = Pick<I, keyof I>;
type overwrite = Overwrite<C1, C2>;
- EOF -
1、TypeScript 高级类型及用法
2、字节 React + TypeScript 实践总结篇
3、基于 Vue3 和 TypeScript 项目大量实践后的思考
觉得本文对你有帮助?请分享给更多人
推荐关注「」,提升前端技能
点赞和在看就是最大的支持??
Powered by 小羊羔外链网 8.0.20
©2015 - 2023 小羊羔外链网
您的IP:44.201.72.250,2023-09-30 20:58:12,Processed in 0.07104 second(s).