TypeScript工具類型集合

輔助工具類型

  1. 對(duì)于交叉類型的結(jié)構(gòu)恍风,F(xiàn)latten 能夠?qū)⑺蛊綖閱螌拥膶?duì)象結(jié)構(gòu)
type Flatten<T> = { [K in keyof T]: T[K] };

屬性修飾類型工具

  1. 深度可選參數(shù)
type DeepPartial<T extends object> = {
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
  1. 深度必選參數(shù)
type DeepRequired<T extends object> = {
  [K in keyof T]-?: T[K] extends object ? DeepRequired<T[K]> : T[K];
};
  1. 深度只讀參數(shù)
// 也可以記作 DeepImmutable
type DeepReadonly<T extends object> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};
  1. 深度可變參數(shù)
type DeepMutable<T extends object> = {
  -readonly [K in keyof T]: T[K] extends object ? DeepMutable<T[K]> : T[K];
};
  1. 從聯(lián)合類型剔除 null | undefined
    • 在開啟 --strictNullChecks 下才能正常工作蹦狂。
type NonNullable<T> = T extends null | undefined ? never : T;

type DeepNonNullable<T extends object> = {
  [K in keyof T]: T[K] extends object
    ? DeepNonNullable<T[K]>
    : NonNullable<T[K]>;
};

基于部分屬性修飾的類型工具

  • 拆分對(duì)象結(jié)構(gòu),那不就是內(nèi)置工具類型一節(jié)中講到的結(jié)構(gòu)工具類型朋贬,即 Pick 與 Omit凯楔?
  • 三個(gè)屬性的對(duì)象全部變?yōu)榭蛇x,那不就是屬性修飾锦募?豈不是可以直接用上面剛學(xué)到的遞歸屬性修飾摆屯?
  • 組合兩個(gè)對(duì)象類型,也就意味著得到一個(gè)同時(shí)符合這兩個(gè)對(duì)象類型的新結(jié)構(gòu)糠亩,那不就是交叉類型虐骑?
  1. 將一個(gè)對(duì)象的部分屬性標(biāo)記為可選
/**
 * T: 需要處理的對(duì)象類型
 * K: 需要標(biāo)記為可選的屬性, 必須為 T 內(nèi)部的屬性, 對(duì)象屬性組成的字面量聯(lián)合類型
 */
type MarkPropsAsOptional<
  T extends object,
  K extends keyof T = keyof T
> = Flatten<Partial<Pick<T, K>> & Omit<T, K>>;

type MarkPropsAsOptionalStruct = MarkPropsAsOptional<
  {
    foo: string;
    bar: number;
    baz: boolean;
  },
  "bar"
>;
  1. 將一個(gè)對(duì)象的部分屬性標(biāo)記為必須
type MarkPropsAsRequired<
  T extends object,
  K extends keyof T = keyof T
> = Flatten<Omit<T, K> & Required<Pick<T, K>>>;
  1. 將一個(gè)對(duì)象的部分屬性標(biāo)記為只讀
type MarkPropsAsReadonly<
  T extends object,
  K extends keyof T = keyof T
> = Flatten<Omit<T, K> & Readonly<Pick<T, K>>>;
  1. 將一個(gè)對(duì)象的部分屬性不只讀(可變)
type MarkPropsAsMutable<
  T extends object,
  K extends keyof T = keyof T
> = Flatten<Omit<T, K> & Mutable<Pick<T, K>>>;
  1. 講一個(gè)對(duì)象的部分屬性剔除 null | undefined
type MarkPropsAsNonNullable<
  T extends object,
  K extends keyof T = keyof T
> = Flatten<Omit<T, K> & NonNullable<Pick<T, K>>>;

結(jié)構(gòu)工具

  1. 基于期望的類型去拿到所有此類型的屬性名, Pick 出所有函數(shù)類型的值
type FuncStruct = (...args: any[]) => any;

type FunctionKeys<T extends object> = {
  [K in keyof T]: T[K] extends FuncStruct ? K : never;
}[keyof T];
// 對(duì)上面的解釋
type Tmp<T extends object> = {
  [K in keyof T]: T[K] extends FuncStruct ? K : never;
};

type Res = Tmp<{
  foo: () => void;
  bar: () => number;
  baz: number;
}>;

type ResEqual = {
  foo: 'foo';
  bar: 'bar';
  baz: never;
};
type WhatWeWillGet = Res[keyof Res]; // 'foo' | 'bar'

type WhatWillWeGetEqual1 = Res["foo" | "bar" | "baz"];
type WhatWillWeGetEqual2 = Res["foo"] | Res["bar"] | Res["baz"];
type WhatWillWeGetEqual3 = "foo" | "bar" | never;
  1. 基于鍵值類型查找屬性, 將預(yù)期類型也作為泛型參數(shù)
// 我們預(yù)期查找的類型, 第二個(gè)參數(shù)
type ExpectedPropKeys<T extends object, valueType> = {
  [Key in keyof T]-?: T[Key] extends valueType ? Key : never;
}[keyof T];

type PickByValueType<T extends object, valueType> = Pick<
  T,
  ExpectedPropKeys<T, valueType>
>;

// {
//   foo: string;
// }
type PickResult1 = PickByValueType<{ foo: string; bar: number }, string>;

// {
//   foo: string;
//   bar: number;
// }
type PickResult2 = PickByValueType<
  { foo: string; bar: number; baz: boolean },
  string | number
>;
// OmitByValueType 也是類似的,我們只需要一個(gè)和 ExpectedPropKeys 作用相反的工具類型即可赎线,比如來(lái)個(gè) FilteredPropKeys廷没,只需要調(diào)換條件類型語(yǔ)句結(jié)果的兩端

type FilteredPropKeys<T extends object, ValueType> = {
  [Key in keyof T]-?: T[Key] extends ValueType ? never : Key;
}[keyof T];

type OmitByValueType<T extends object, ValueType> = Pick<
  T,
  FilteredPropKeys<T, ValueType>
>;

type OmitRes1 = OmitByValueType<{ foo: string; bar: number }, string>;
type OmitRes2 = OmitByValueType<
  { foo: string; bar: number; baz: boolean },
  string | number
>;

集合工具

// 一維
// 并集
type Concurrence<A, B> = A | B
// 交集
type Intersection<A, B> = A extends B ? A : never
// 差集
type Difference<A, B> = A extends B ? never : A
// 補(bǔ)集
type Complement<A, B extends A> = Difference<A, B>
  1. 屬性名并集
// 實(shí)現(xiàn)對(duì)象屬性名的版本
type PlainObjectType = Record<string, any>;

// 屬性名并集
type ObjectKeysConcurrence<
  T extends PlainObjectType,
  U extends PlainObjectType
> = keyof T | keyof U;
  1. 屬性名交集
// 屬性名交集
type ObjectKeysIntersection<
  T extends PlainObjectType,
  U extends PlainObjectType
> = Intersection<keyof T, keyof U>;
  1. 屬性名差集
// 屬性名差集
export type ObjectKeysDifference<
  T extends PlainObjectType,
  U extends PlainObjectType
> = Difference<keyof T, keyof U>;
  1. 屬性名補(bǔ)集
// 屬性名補(bǔ)集
export type ObjectKeysComplement<
  T extends U,
  U extends PlainObjectType
> = Complement<keyof T, keyof U>;
  1. 提取首個(gè)參數(shù)類型
type FunctionType = (...args: any) => any;

type FirstParameter<T extends FunctionType> = T extends (
  arg: infer P,
  ...args: any
) => any
  ? P
  : never;
  1. 提取最后一個(gè)參數(shù)
type FunctionType = (...args: any) => any;
type LastParameter<T extends FunctionType> = T extends (arg: infer P) => any
  ? P
  : T extends (...args: infer R) => any
  ? R extends [...any, infer Q]
    ? Q
    : never
  : never;

type FuncFoo = (arg: number) => void;
type FuncBar = (...args: string[]) => void;
type FuncBaz = (arg1: string, arg2: boolean) => void;

type FooLastParameter = LastParameter<FuncFoo>; // number
type BarLastParameter = LastParameter<FuncBar>; // string
type BazLastParameter = LastParameter<FuncBaz>; // boolean
  1. 提取 Promise 內(nèi)部值類型的工具類型 PromiseValue
// 首先提取到 then 方法中的函數(shù)類型,再通過(guò)這個(gè)函數(shù)類型的首個(gè)參數(shù)來(lái)提取出實(shí)際的值垂寥。


type Awaited<T> = T extends null | undefined
  ? T
  : T extends object & { then(onfulfilled: infer F): any }
  ? F extends (value: infer V, ...args: any) => any
    ? Awaited<V>
    : never
  : T;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末颠黎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子滞项,更是在濱河造成了極大的恐慌狭归,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件文判,死亡現(xiàn)場(chǎng)離奇詭異过椎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)戏仓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門潭流,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人柜去,你說(shuō)我怎么就攤上這事〔鹜穑” “怎么了嗓奢?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)浑厚。 經(jīng)常有香客問我股耽,道長(zhǎng)根盒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任物蝙,我火速辦了婚禮炎滞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘诬乞。我一直安慰自己册赛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布震嫉。 她就那樣靜靜地躺著森瘪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪票堵。 梳的紋絲不亂的頭發(fā)上扼睬,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音悴势,去河邊找鬼窗宇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛特纤,可吹牛的內(nèi)容都是我干的军俊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼叫潦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蝇完!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起矗蕊,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤短蜕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后傻咖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體朋魔,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年卿操,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了警检。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡害淤,死狀恐怖扇雕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情窥摄,我是刑警寧澤镶奉,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響哨苛,放射性物質(zhì)發(fā)生泄漏鸽凶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一建峭、第九天 我趴在偏房一處隱蔽的房頂上張望玻侥。 院中可真熱鬧,春花似錦亿蒸、人聲如沸凑兰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)票摇。三九已至,卻和暖如春砚蓬,著一層夾襖步出監(jiān)牢的瞬間矢门,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工灰蛙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留祟剔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓摩梧,卻偏偏與公主長(zhǎng)得像物延,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子仅父,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容