一些在TypeScript上費(fèi)過(guò)時(shí)間的地方總結(jié)
記錄一些自己在ts上費(fèi)過(guò)時(shí)間的地方。
(先吐個(gè)槽:stackoverflow是真的啥都有,百度是真的沒(méi)法用)
坑
as斷言的兼容性誤解,如"a" as "b"這種代碼是不會(huì)報(bào)錯(cuò)的。
interface和type的不一致行為(初遇還以為自己寫(xiě)錯(cuò)類(lèi)型,一臉懵逼的):
type Type = {
key: "value"
}
interface Interface {
key: "value"
}
type 似乎沒(méi)差別都是true = Type extends Interface ? Type extends Interface ? true : false : false
type 坑點(diǎn) = {
[key: string]: 坑點(diǎn)
} | string
type 測(cè)試<T> = T extends 坑點(diǎn) ? true : false
type 這個(gè)是true = 測(cè)試<Type>
type 這個(gè)是false = 測(cè)試<Interface>
github上官方有說(shuō)明,是故意留這么個(gè)坑的。說(shuō)是因?yàn)閕nterface可擴(kuò)展(同名自動(dòng)合并),所以不便檢測(cè)。
用泛型實(shí)現(xiàn)函數(shù)重載的效果時(shí),在函數(shù)的實(shí)現(xiàn)中,會(huì)因泛型不具備具體約束,導(dǎo)致經(jīng)常需要使用as強(qiáng)制斷言。
//差不多這意思,下面的代碼懶得實(shí)際測(cè)了🙃
//fns是個(gè)函數(shù)索引表,TFns是索引表的const類(lèi)型
function 重載失敗<T extends keyof TFns>(fn:T, params: Parameters<fns[T]>){
fns[fn](...params)//在實(shí)現(xiàn)中聯(lián)合類(lèi)型不會(huì)縮小,所以會(huì)報(bào)錯(cuò)
//錯(cuò)誤應(yīng)該像是 不能將方法1的參數(shù)傳給方法2 這種
}
//但外部使用時(shí),符合類(lèi)型的語(yǔ)義也沒(méi)啥事
擴(kuò)展運(yùn)算符并不符合直觀感受: [...string[], number]這種類(lèi)型在使用時(shí)是符合閱讀時(shí)的直覺(jué)的(要求數(shù)組末尾是number元素),但是[...string[], null, ...object[], number]這種不行,不會(huì)按順序來(lái)也不會(huì)報(bào)錯(cuò)。新版ts加了禁止連續(xù)解構(gòu)的規(guī)則,這種類(lèi)型直接不讓寫(xiě)了。
其實(shí)這里有解決辦法,但是寫(xiě)出來(lái)的類(lèi)型簡(jiǎn)直沒(méi)法看(幾十行,包含大量extends充當(dāng)類(lèi)型的if判斷),就不貼了 下面貼代碼:
//需要的類(lèi)型:[...number[], "middle-element", ...boolean[]]
//上面的寫(xiě)法是無(wú)效的,只是示意下面的類(lèi)型代碼是干什么用的(實(shí)現(xiàn)上面示意的類(lèi)型約束)
type Elem = number | boolean | "middle-element";
type Last<T extends any[]> = T extends [infer _]
? never
: T extends [...infer _, infer Tl]
? Tl
: never
type HandleEmpty<T extends any[], Data> = T['length'] extends 0 ? never : Data
type Validation<Params extends any[], Cache extends Elem[] = []> =
Params extends []
? Cache['length'] extends 0
? never
: Cache
: Params extends [infer Fst, ...infer Rest]
? Cache extends []
? Fst extends number
? HandleEmpty<Rest, Validation<Rest, [...Cache, Fst]>>
: never
: Fst extends number
? Last<Cache> extends number
? HandleEmpty<Rest, Validation<Rest, [...Cache, Fst]>>
: never
: Fst extends "middle-element"
? Last<Cache> extends number
? HandleEmpty<Rest, Validation<Rest, [...Cache, Fst]>>
: never
: "middle-element" extends Cache[number]
? Fst extends boolean
? Validation<Rest, [...Cache, Fst]>
: never
: never
: never
type IsNever<T> = [T] extends [never] ? true : false;
function check<
Params extends Elem[],
IsValid extends Validation<Params>
>(...arr: IsNever<IsValid> extends true ? [never] : [...Params]) {
return arr
}
const 正常 = check(1, 'middle-element', false)
const 報(bào)錯(cuò) = check(false, "middle-element", 2)
進(jìn)階操作
對(duì)象名重映射:
//{ "new-a":any; "new-b":any }
type 重映射 = {
[K in "a" | "b" as `new-${K}`]: any
}
聯(lián)合類(lèi)型的拆分:用infer關(guān)鍵字可以實(shí)現(xiàn)對(duì)聯(lián)合類(lèi)型的拆分。
//"a1"|"b2"
type 拆分成功<_Keys = keyof { a: 1, b: 2 }> = _Keys extends infer K ?
`${Extract<K, string>}${{ a: 1, b: 2 }[Extract<K, _Keys>]}`
: never
//注意:(截止ts4.4.4)直接`keyof Obj extends infer K`無(wú)法分割聯(lián)合類(lèi)型,原因不明(懶得查😁)。
//結(jié)果是"a1"|"a2"|"b1"|"b2"
type 拆分失敗 = keyof { a: 1, b: 2 } extends infer K ?
`${Extract<K, string>}${{ a: 1, b: 2 }[Extract<K, "a" | "b">]}`
: never
元組類(lèi)型:
- 實(shí)際(非類(lèi)型)參數(shù)有時(shí)候需要通過(guò)as const明確定義為元組類(lèi)型。
- 元組類(lèi)型可以通過(guò)元組["length"]獲取準(zhǔn)確的長(zhǎng)度,而不是number。
- 元組類(lèi)型在通過(guò)泛型參數(shù)使用時(shí),有時(shí)候需要通過(guò)加個(gè)[]|寫(xiě)成元組 extends []|any[]這種方式來(lái)避免被解析為普通的不定長(zhǎng)數(shù)組類(lèi)型。
遞歸類(lèi)型:用...infer More可以實(shí)現(xiàn)對(duì)數(shù)組類(lèi)型的遞歸。
type 轉(zhuǎn)換器<T> = T extends string ? "str" : null
//進(jìn)去是個(gè)[string,number,string],出來(lái)就會(huì)是["str",null,"str"]
type 遞歸<
輸入源 extends any[],
內(nèi)部的類(lèi)型緩存 extends any[] = []
> = 輸入源 extends [any, ...infer 剩余元素] ?
遞歸<剩余元素, [...內(nèi)部的類(lèi)型緩存, 轉(zhuǎn)換器<輸入源[0]>]>
: 輸入源
零碎
- &可以代替extends對(duì)type使用,interface除了可以合并同名的類(lèi)型,其它的沒(méi)啥差別了。
- ts具有豐富的內(nèi)建類(lèi)型,挑幾個(gè)例子:
- ReturnType<函數(shù)類(lèi)型>,獲取函數(shù)類(lèi)型的返回值的類(lèi)型。
- Uncapitalize<字符串>,將輸入的字符串類(lèi)型的首字母鎖定為小寫(xiě)(其它還有首字母大寫(xiě)、全小寫(xiě)、全大寫(xiě))。
新手建議去官網(wǎng)翻文檔。
入了ts坑后,可以沒(méi)事關(guān)注下版本更新帶來(lái)的新特性(玩法)。
總結(jié)
到此這篇關(guān)于在TypeScript上費(fèi)過(guò)時(shí)間的地方總結(jié)的文章就介紹到這了,更多相關(guān)ts費(fèi)時(shí)間的地方內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用 Chrome Dev Tools 進(jìn)行頁(yè)面性能分析的步驟說(shuō)明(前端性能優(yōu)化)
這篇文章主要介紹了利用 Chrome Dev Tools 進(jìn)行頁(yè)面性能分析的步驟說(shuō)明(前端性能優(yōu)化),本文給大家介紹的非常想詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02
關(guān)于moment.js的常用方法及使用說(shuō)明
這篇文章主要介紹了關(guān)于moment.js的常用方法及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
JS如何設(shè)置cookie有效期為當(dāng)天24點(diǎn)并彈出歡迎登陸界面
這篇文章主要介紹了JS如何設(shè)置cookie有效期為當(dāng)天24點(diǎn)并彈出歡迎登陸界面的代碼,代碼比較簡(jiǎn)單,好理解,需要的朋友可以參考下2016-08-08
JS簡(jiǎn)單實(shí)現(xiàn)數(shù)組去重的方法分析
這篇文章主要介紹了JS簡(jiǎn)單實(shí)現(xiàn)數(shù)組去重的方法,結(jié)合具體實(shí)例形式分析了javascript數(shù)組遍歷、判斷實(shí)現(xiàn)去重復(fù)的相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2017-10-10
JavaScript高級(jí)程序設(shè)計(jì) 客戶端存儲(chǔ)學(xué)習(xí)筆記
JavaScript高級(jí)程序設(shè)計(jì) 客戶端存儲(chǔ)學(xué)習(xí)筆記,在客戶端用于存儲(chǔ)會(huì)話信息2011-09-09
JS PHP字符串截取函數(shù)實(shí)現(xiàn)原理解析
這篇文章主要介紹了JS PHP字符串截取函數(shù)實(shí)現(xiàn)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08

