大家好败晴,我是愛水文的蘇先生房轿,一名從業(yè)5年+的前端愛好者粤攒,致力于用最通俗的文字分享前端知識的酸菜魚
github與好文
前言
TypeScript作為一個圖靈完備的類型系統(tǒng)冀续,可以幫助我們提高項目的可維護性并在開發(fā)階段就能幫助發(fā)現(xiàn)一些潛在的錯誤琼讽。時至今日,無論是我們平時工作中在項目里使用還是學習一些第三方的庫源碼洪唐,都能看到它的身影。因此學習它也已經(jīng)成為了一種必然
實際上吼蚁,當所有人都會而你不會的時候凭需,你便是那個被時代拋棄的人。你要非說前端最重要的是業(yè)務實現(xiàn)能力肝匆,是js粒蜈。那我要拿出"你js這么秀,為啥還學不會ts旗国?"枯怖,你又當如何應對?
APIS
Partial
- 功能
將源類型中的key全部變成可選并返回一個新的類型
- 實現(xiàn)
我們知道能曾,一個可選的屬性定義大致長這樣度硝,也就是說,我們只需要給屬性名后邊增加個?標記就可以了
interface Person{
name?:string;
age?:number;
}
對于Partial的接收參數(shù)來說寿冕,其擁有的key是不固定的蕊程,所以我們必須要想辦法拿到每一個key。在TypeScript中驼唱,keyof關鍵字可以將interface轉換成由鍵名組成的聯(lián)合類型藻茂。如下,我們拿到的新的聯(lián)合類型為T='name'|'age'
type T = keyof Person
現(xiàn)在我們只需要對聯(lián)合類型進行遍歷就能拿到每一個key了玫恳,在TypeScript中這對應in關鍵字辨赐。至此,我們只需要為每次拿到的key添加?標記就可以將原來的key變成可選了,最后再使用T[K]將對應的類型從Person中取出即可
type Partial<T> = {
[K in keyof T]?: T[K];
};
Required
- 功能
與Partial相反京办,將key變成必選掀序,并返回新的類型
- 實現(xiàn)
這和Partial的實現(xiàn)思路一樣,我們只需要消掉?即可臂港,這在TypeScript中使用-來進行消除
type Partial<T> = {
[K in keyof T]-?: T[K];
};
Readonly
- 功能
將key變成只讀的森枪,并返回一個新的類型
- 實現(xiàn)
這和Partial的實現(xiàn)思路也一樣视搏,我們只需要為其添加readonly關鍵字即可
type Partial<T> = {
readonly [K in keyof T]: T[K];
};
Pick
- 功能
挑選指定的key,并返回一個新的類型
- 實現(xiàn)
想要從源類型中挑選指定的值县袱,首先我們需要將其作為參數(shù)傳遞給Pick浑娜,如下,我們通過泛形K來標識將來要挑選的值式散,至于泛形T筋遭,自然就是源類型了
type Pick<T,K>{}
比較好理解的是,我們的K不能是隨意的暴拄,它受到T的約束漓滔,這個我們使用extends來實現(xiàn),可以看到我們的K實際上是一個聯(lián)合類型
type Pick<T,K extends keyof T>{}
最后我們只需要遍歷這個聯(lián)合類型乖篷,并重新生成一個新的類型就可以了响驴,至于k的類型,和前邊一樣從源類型中提取即可
type Pick<T,K extends keyof T>{
[P in K]:T[P]
}
Omit
- 功能
從一個指定的對象類型中排除指定的key
- 實現(xiàn)
首先撕蔼,它包含兩個泛形參數(shù)T和U豁鲤,T是源類型,U是要排除的key
type Omit<T,U>
第二步鲸沮,我們來思考U是否需要約束琳骡,它應且本應只包含T中的key,傳遞不存在的實際上并不參與類型運算
type Omit<T,U extends keyof T>
第三步讼溺,我們拿到所有的key楣号,至于對應的類型,由于我們已經(jīng)約束了U怒坯,所以可以放心通過key從T中取即可
type Omit<T,U extends keyof T> = {
[K in keyof T]:T[K]
}
最后就是對K進行類型判斷炫狱,如果它是U的子類型我們就排除,否則就保留
type Omit<T,U extends keyof T> = {
[K in keyof T as P extends U ? never : P]:T[P]
}
- 擴展解法
使用Pick和下文實現(xiàn)的Exclude也可以實現(xiàn)同樣的功能敬肚,有興趣的可以自己動手寫一下哦
Exclude
- 功能
這個從功能上講和Omit有點像毕荐,不過它主要用于聯(lián)合類型。從第一個聯(lián)合類型參數(shù)中艳馒,將第二個聯(lián)合類型中出現(xiàn)的聯(lián)合項排除
- 實現(xiàn)
首先我們確定了Exclude接收兩個參數(shù)
type Exclude<T,U>
我們在功能解釋中說明了這兩個泛形一般為聯(lián)合類型憎亚,那么是否需要對T和U進行約束呢?答案是不需要弄慰!因為尺有所短第美,寸有所長,它善于處理聯(lián)合類型不代表它只能處理聯(lián)合類型
那么我們如何做到和interface中那樣拿到每一個key呢陆爽?只有拿到了每一個key值我們才有機會去進行比較以確定排除什往。在TypeScript中,當使用extends對一個聯(lián)合類型執(zhí)行判斷時慌闭,它會拿每一個key來分別比較别威,故我們拿每一個T中的key判斷是否是U的子類型躯舔,是就設置為nerver標識排除就好了
type Exclude<T,U> = T extends U ? never : T
打call時間:
至此,十二個內置工具類型我們已經(jīng)學完一半了省古,我想你一定累了粥庄,所以我們休息一下
我目前正在開發(fā)一個名為unplugin-router的項目,它是一個約定式路由生成的庫,目前已支持在webpack和vite中使用豺妓,也已完成對vue-router3.x和vue-router4.x的支持惜互,且已經(jīng)接入到公司的一個vite3+vue3的項目中
不過受限于工作時間進度比較慢,在此尋找志同道合的朋友一起來完成這件事琳拭,后續(xù)計劃對功能做進一步的完善训堆,比如支持@hmr注解、支持權限路由等白嘁,也有對react路由和svelte路由的支持計劃坑鱼,以及除了webpack和vite這兩個之外的構建工具的支持,還有單元測試的編寫.....
Extract
- 功能
從T類型中提取可以賦值給U的類型絮缅,返回一個聯(lián)合類型
- 實現(xiàn)
同樣的它應有兩個泛形姑躲,不過不需要對其進行類型約束
type Extract<T,U>
前文我們已經(jīng)說過了,對于泛形是聯(lián)合類型時盟蚣,extends關鍵字會進行分配比較,所以我們相當于在拿T中的每一個key去判斷是否是U的子類型卖怜,不是就過濾掉
type Extract<T,U> = T extends U ? T : never
Record
- 作用
構造具有類型T的一組屬性K的類型屎开,返回新的對象類型
- 實現(xiàn)
同樣接受兩個泛形
type Record<T,U>
這里需要對泛形進行約束,對于泛形T马靠,必須為聯(lián)合類型
type Record<T extends keyof any,U>
然后只需要遍歷每一個key并為其設置類型為U即可
type Record<T,U> = {
[k in T]:U
}
NonNullable
- 功能
從給定的類型T中排除undefined和null
- 實現(xiàn)
我們通過條件判斷是否是null或undefined奄抽,是就設置為never就好了
type NonNullable<T> = T extends null|undefined ? never : T
- 擴展解法
通過空類型取交叉也可以達到同樣的效果,感興趣的可以自己嘗試下哦
Parameters
- 功能
提取函數(shù)參數(shù)的類型
- 實現(xiàn)
首先甩鳄,它接受一個函數(shù)的ts定義
type Parameters<T extends (...args:any)=>any>
接著逞度,我們對args進行推斷,這需要用到infer關鍵字
type Parameters<T extends (...args:any)=>any> T extends (...args:infer P)=>any ? P : never
ReturnType
- 功能
獲取函數(shù)的返回值類型
- 實現(xiàn)
和Parameters一樣妙啃,在返回值位置處進行推斷
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
ThisParameterType
- 功能
獲取函數(shù)的this類型
- 實現(xiàn)
和Parameters一樣档泽,同樣借助infer關鍵字在條件類型中推斷
type ThisParameterType<T extends (this:any,...args: any) => any> = T extends (this infer S,...args: any) => infer S ? S : any;