[TS進階][BFE-TS]1-20題

前言

BFE是一個前端面試及學習網站,這篇文章將帶你學習並理解BFE-TS1-20題,進行TS能力進階。前端

須要必定的TS基礎git

效果

學習並理解這些題目可讓你的TS能力飆升。github

題目

1-15 Utility types 實現

1-15題都是TS的內置Utility types,有用但簡單,不過多描述。面試

1. implement Partial

映射類型添加 ? 標識typescript

type Partial<T> = {
    [P in keyof T]?: T[P];
};
複製代碼

2. implement Required

映射類型刪除 ? 標識數組

type Required<T> = {
    [P in keyof T]-?: T[P];
};
複製代碼

3. implement Readonly

映射類型添加 readonly 標識markdown

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};
複製代碼

4. implement Record

通常用於快速創建簡單對象類型,K 是建立對象類型的索引類型,T 則是建立對象類型的值類型frontend

type Record<K extends keyof any, T> = {
    [P in K]: T;
};
複製代碼

5. implement Pick

選擇部分 T 中的索引類型後將其映射成新的對象類型分佈式

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};
複製代碼

6. implement Omit

選擇部分 T 中的索引類型後將其從原來的 keyof T 中剔除映射成新的對象類型函數

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
複製代碼

7. implement Exclude

經過分佈式條件類型(Distributive Conditional Types) 進行篩選,將知足條件的返回 never,由於聯合類型忽略 never 從而達到剔除的做用

type Exclude<T, U> = T extends U ? never : T;
複製代碼

8. implement Extract

同上,返回相反,只將知足條件的返回,不知足則被剔除

type Extract<T, U> = T extends U ? T : never;
複製代碼

9. implement NonNullable

剔除 null | undefined 類型,代表非空

type NonNullable<T> = T extends null | undefined ? never : T;
複製代碼

10. implement Parameters

經過 infer 推斷函數參數並返回

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
複製代碼

11. implement ConstructorParameters

經過 infer 推斷 new 構造函數參數並返回, TS 中經過 new (args) => any 聲明這個函數被 new 調用時所需的參數和返回值

type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;
複製代碼

12. implement ReturnType

經過 infer 推斷函數返回值

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
複製代碼

13. implement InstanceType

經過 infer 推斷 new 後返回的類型

type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;
複製代碼

14. implement ThisParameterType

經過 infer 推斷函數的 this 類型

type ThisParameterType<T> = T extends (this: infer U, ...args: any[]) => any ? U : unknown;
複製代碼

15. implement OmitThisParameter

因推斷時自動忽略函數的 this 類型,所以直接經過推斷後的參數類型和返回值類型包裝成個函數返回便可

type OmitThisParameter<T> = unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T;
複製代碼

上面爲 TS 源碼,但實際經過 BFE 測試還能夠這麼寫,Parameters 本質仍是推斷,所以會忽略 this:

type MyOmitThisParameter<T> = T extends (...args: any) => any ? ( ...args: Parameters<T> ) => ReturnType<T> : T
複製代碼

16. implement FirstChar<T>

實現FirstChar<T>類型:

type A = FirstChar<'BFE'> // 'B'
type B = FirstChar<'dev'> // 'd'
type C = FirstChar<''> // never
複製代碼

答案

目前TS支持字符串使用infer推斷,語法和模板字符串類似,所以使用infer便可完成。

type FirstChar<T extends string> = T extends `${infer T}${any}` ? T : never
複製代碼

17. implement LastChar<T>

實現LastChar<T>類型:

type A = LastChar<'BFE'> // 'E'
type B = LastChar<'dev'> // 'v'
type C = LastChar<''> // never
複製代碼

答案

一樣使用infer推斷字符串中的類型,模板字符串中的推斷必須保證前面的${any}匹配一個,身下的都丟給最後的${any}匹配。

舉個栗子:

${infer A}${infer B}${infer C}匹配'ab'A在前面匹配了'a'B也在前面所以匹配一個'b',剩下的都丟給C,由於沒有剩餘的了,因此C匹配到了''

曉得如何匹配了,那麼再加上遞歸便可作出來

type LastChar<T extends string> = T extends `${infer F}${infer R}`
  ? R extends ''
    ? F
    : LastChar<R>
  : never
複製代碼

過程:

'BFE' => 
	F -> 'B', R -> 'FE'
	R isn't '' 
	LastChar<'FE'>
		F -> 'F', R -> 'E'
		R isn't ''
		LastChar<'E'>
			F -> 'E', R -> ''
			R is ''
				F -> 'E'
複製代碼

即經過一直拿出當前字符串類型的第一位而後判斷剩下的是否爲''是的話就是最後一個了,不是就繼續遞歸剩下的。

18. implement TupleToUnion<T>

type Foo = [string, number, boolean]

type Bar = TupleToUnion<Foo> // string | number | boolean
複製代碼

答案

這題考察的是索引訪問類型Indexed Access Types,咱們可使用索引訪問類型來查找另外一種類型上的特定屬性,keyof能夠得到某類型的全部可訪問的索引類型。

type TupleToUnion<T extends any[]> = T[number]
複製代碼

數組類型有個特殊的索引類型number,能夠經過arr[number]獲取一個數組中元素的類型。

19. implement FirstItem<T>

type A = FirstItem<[string, number, boolean]> // string
type B = FirstItem<['B', 'F', 'E']> // 'B'
複製代碼

答案

現在元組能夠經過infer推斷其中類型,和16. FirstChar<T>同理

type FirstItem<T extends any[]> = T extends [infer T, ...any] ? T : never
複製代碼

20. implement IsNever<T>

type A = IsNever<never> // true
type B = IsNever<string> // false
type C = IsNever<undefined> // false
複製代碼

答案

粗略一看,霍,介不容易嘛?自信寫出

type IsNever<T> = T extends never ? true : false
複製代碼

可是呢,never當泛型直接傳入時,會直接返回never,即IsNever<never>返回never和須要的true不符合,所以行不通。

那有沒有辦法能夠避開這個現象呢,有,和避開啓動分佈式條件類型的方法一致:

type Blah<T> = Box<T> extends Whatever ? A : B
type Blah<T> = Whatever extends T ? A : B
複製代碼

包裝TT做爲被繼承的。

never extends T是咱們想要的麼?never是全部的類型基類所以它繼承誰都是true,因此不符合要求。

因此咱們要選擇包裝T,包裝T的方式不少種,這裏選擇了最簡單的一種,包裝成元組:

type IsNever<T> = [T] extends [never] ? true : false
複製代碼

總結

前面20題的難度說不上高,可是能提高對infer以及一些現象和用法的理解。

github倉庫地址

若是本文對你有所幫助,麻煩點個贊支持一些,謝謝:)

相關文章
相關標籤/搜索