點擊上方 程式員成長指北,關注公眾號
回復1,加入高級Node交流群
在學習ts原始碼的時候,發現很多泛型還是看不懂,于是想寫一篇文章,總結一下常用的泛型,
基礎必備知識
聯合型別vs交叉型別
// 聯合型別
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 提取欄位
// 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 欄位,
方式二:Omit 反向獲取
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>;
特殊的情況:Overwrite(覆寫)
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>;
Node 社群
我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學習感興趣的話(后續有計劃也可以),我們可以一起進行Node.js相關的交流、學習、共建,下方加 考拉 好友回復「Node」即可,

“分享、點贊、在看” 支持一波👍
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/349635.html
標籤:其他
上一篇:jquery物件拷貝
