TypeScript 中的泛型你真搞懂了嗎?
點(diǎn)擊上方?程序員成長(zhǎng)指北,關(guān)注公眾號(hào)
回復(fù)1,加入高級(jí)Node交流群
在學(xué)習(xí)ts源碼的時(shí)候,發(fā)現(xiàn)很多泛型還是看不懂,于是想寫一篇文章,總結(jié)一下常用的泛型。
基礎(chǔ)必備知識(shí)
聯(lián)合類型vs交叉類型
//?聯(lián)合類型
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()?{}?};
聯(lián)合類型使用 “|”表示或的關(guān)系, 滿足其中的一個(gè)情況即可。
interface?Bird?{
??name:?string;
??fly():?void;
}
interface?Person?{
??name:?string;
??talk():?void;
}
type?BirdPerson?=?Bird?&?Person;
let?p:?BirdPerson?=?{?name:?"zhufeng",?fly()?{},?talk()?{}?};
交叉類型使用“&”,表示與的關(guān)系,需要滿足所有的情況。
內(nèi)置條件類型
type?Extract?=?T?extends?U???T?:?never;
type?Exclude?=?T?extends?U???never?:?T;
type?NonNullable?=?T?extends?null?|?undefined???never?:?T;
type?N?=?NonNullable<string?|?number?|?null?|?undefined>;//?刪除null和undifined;
type?E?=?Exclude<string?|?number,?string>;?//?排除關(guān)系?輸出?string;
type?I?=?Extract<string?|?number,?string>;?//?包含關(guān)系?輸出?number;
函數(shù)的類型推斷
獲取函數(shù)返回值的類型
type?ReturnType?=?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,
};
獲取函數(shù)參數(shù)的類型
type?Parameters?=?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]
泛型進(jìn)階
很多人對(duì)于泛型的理解還停留在基礎(chǔ)的層面,我講站在集合的視角去理解一下什么叫泛型。
案例一:字段的提取
給定一個(gè)接口 Persion, ?里面有name,age,visiable,三個(gè)字段,現(xiàn)在的要求是:得到一個(gè)新的接口,里面只有name,age。一般人常見的思路:
interface?Person?{
??name:?string;
??age:?number;
??visiable:?boolean;
}
interface?Person1?{
??name:?string;
??age:?number;
}
我們從寫一個(gè)接口,就可以達(dá)到要求。但是這樣子的寫法,顯得十分冗余。其實(shí)ts提供了方法,讓我們可以實(shí)現(xiàn),讓我們一起看一下的例子。
方式一:Pick 提取字段

//?pick?的原理
//?type?Pick?=?{?[P?in?K]:?T[P]?};
interface?Person?{
??name:?string;
??age:?number;
??visiable:?boolean;
}
type?Person1?=?Pick'name'|'age'>?;
Person1 就包含 name,age 字段。
方式二:Omit 反向獲取

interface?Person?{
??name:?string;
??age:?number;
??visiable:?boolean;
}
type?Exclude?=?T?extends?U???never?:?T;
type?Omitextends?keyof?T>?=?Pick>;
type?Person2?=?Omit"age">;
案例二:兩個(gè)接口的操作
我們把一個(gè)接口當(dāng)作一個(gè)集合,那么兩個(gè)集合的操作主要有:并集,交集,差集。
交集

type?Extract?=?T?extends?U???T?:?never;
type?Intersectionextends?object,?U?extends?object>?=?Pick<
??T,
??Extract?&?Extract
>;
type?C1?=?{?name:?string;?age:?number;?visible:?boolean?};
type?C2?=?{?name:?string;?age:?number;?sex:?number?};
type?C3?=?Intersection;
交集的定義:對(duì)于給定的兩個(gè)集合,返回一個(gè)包含兩個(gè)集合中共有元素的新集合。通過Intersection實(shí)現(xiàn)交集,可以獲得一個(gè)新接口,C3只包含 name.age。如上圖。
差集

type?Exclude?=?T?extends?U???never?:?T;
type?Diffextends?object,?U?extends?object>?=?Pick<
??T,
??Exclude
>;
type?C1?=?{?name:?string;?age:?number;?visible:?boolean?};
type?C2?=?{?name:?string;?age:?number;?sex:?number?};
type?C11?=?Diff;
差集的定義:對(duì)于給定的兩個(gè)集合,返回一個(gè)包含所有存在于第一個(gè)集合且不存在于第二個(gè)集合的元素的新集合。通過Diff實(shí)現(xiàn)差集,可以獲得一個(gè)新接口,接口只有visiable。如上圖。
并集

并集的定義:對(duì)于給定的兩個(gè)集合,返回一個(gè)包含兩個(gè)集合中所有元素的新集合。通過Merge實(shí)現(xiàn)并集,可以獲得一個(gè)新接口,接口包含C1,C2 的所有屬性。如上圖。
//Compute的作用是將交叉類型合并
type?Computeextends?any>?=?A?extends?Function???A?:?{?[K?in?keyof?A]:?A[K]?};
type?Omit?=?Pick>;
type?Mergeextends?object,?O2?extends?object>?=?Compute>;
type?C1C2?=?Merge;
特殊的情況: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?&?Intersection
>?=?Pick;
??
type?overwrite?=?Overwrite;
我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。
???“分享、點(diǎn)贊、在看” 支持一波??
