最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

簡單三行代碼函數(shù)實現(xiàn)幾十行Typescript類型推導(dǎo)

 更新時間:2023年01月15日 16:41:46   作者:xekin  
這篇文章主要為大家介紹了簡單三行代碼函數(shù)實現(xiàn)幾十行Typescript類型推導(dǎo)的方案示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

場景

最近在設(shè)計一些基礎(chǔ)的項目框架設(shè)計上的 sdk api,比如埋點系統(tǒng)、權(quán)限系統(tǒng)之類的,要提供一些便捷的封裝方法給上層使用。于是遇到了這么個場景。

有一個對象常量里,存了一些方法,例如:

    const METHODS = {
        a: () => "a" as const,
        b: () => "b" as const,
        c: () => "c" as const
    }

然后想要封裝這樣一個 hook 例如 useMethod 給上層的 React 上下文使用:

    type MethodKey = keyof typeof METHODS
    function useMethods(keys: MethodKey[]) {
        return keys.map(key => METHODS[key])
    }
    // case
    const [a, b] = useMethods(['a', 'b'])
    // expect to "a"
    a();

一切都簡簡單單,屬于是日常到不能再日常的代碼,可是當我在 IDE 里挪上去一看,這不對勁呀:

我預(yù)期這里應(yīng)該類型直接就是字符串 a 了,怎么會是個聯(lián)合類型?

摸魚吃瓜式排查

我上上下下看了一遍類型推導(dǎo),發(fā)現(xiàn) keys.map(key => METHODS[key]) 這一句里,key 直接被推導(dǎo)成了 "a" | "b" | "c"。

所以理所當然的結(jié)果也是推導(dǎo)成了 "a" | "b" | "c"

emmm......這還有些麻煩,先單獨寫個類型方法來推導(dǎo)結(jié)果試試,遞歸傳入的數(shù)組泛型,取出每一次的 key 對應(yīng)的 method,再組合為數(shù)組。

 type MethodValue<K extends MethodKey> = typeof METHODS[K]
 type GetMethodValue<T extends MethodKey[]> = T extends [] 
     ? [] 
     : T extends [infer F extends MethodKey, ...infer Rest extends MethodKey[]]
     ? [MethodValue<F>, ...GetMethodValue<Rest>]
     : never 

測試一下:

再將類型回到方法 useMethod 上帶入?yún)s發(fā)現(xiàn)完全不行:

如果強行斷言 map 返回的結(jié)果,則直接會被推導(dǎo)為 never 類型

元組大法

其實不難從代碼里看出,之所以無法推導(dǎo)原因有兩點,第一點是在 Typescript 編譯時這個階段,是無法推導(dǎo)這個函數(shù)泛型傳參的多種形態(tài)中的 key 是怎樣排序的,其次是在 map 方法中,key 值一直被推導(dǎo)成 "a" | "b" | "c" 導(dǎo)致。

所以如果我用元組作為泛型限定值,倒是可以實現(xiàn):

type GetMethodValue<T extends (MethodKey | void)[]> = T extends []
     ? []
     : T extends [infer F extends MethodKey, ...infer Rest extends MethodKey[]] 
     ? [MethodValue<F>, ...GetMethodValue<Rest>] 
     : never 
function useMethods<T extends ['a'?, 'b'?, 'c'?]>(keys: T) {
    return keys.filter((key): key is MethodKey => !!key).map((key) => METHODS[key]) as GetMethodValue<T>
}
const [a, b] = useMethods(['a', 'b'])
const valueA = a()

理解到這,我就思考雖然類型不能自動推導(dǎo)出元組的組合排列方式,但是我卻可以寫一個方法來實現(xiàn)推導(dǎo)聯(lián)合類型生成元組。

    type Permutation<T, U = T> = [T] extends [never]
      ? []
      : U extends T
      ? [U, ...Permutation<Exclude<T, U>>]
      : never;
    // expect to ['a', 'b'] | ['b', 'a']
    type value = Permutation<'a' | 'b'>

這是我之前在寫 TypeChallenge 時寫過的方法,這就派上用場了。

直接將 MethodKey 這個聯(lián)合類型解成元組之后限定泛型 T,最后確實也可以成功推導(dǎo)結(jié)果。

type Permutation<T, U = T> = [T] extends [never]
  ? []
  : U extends T
  ? [U?, ...Permutation<Exclude<T, U>>]
  : never;
type MethodKey = keyof typeof METHODS
type MethodValue<K extends MethodKey> = typeof METHODS[K]
type GetMethodValue<T extends (MethodKey | void)[]> = T extends []
     ? []
     : T extends [infer F extends MethodKey, ...infer Rest extends MethodKey[]] 
     ? [MethodValue<F>, ...GetMethodValue<Rest>] 
     : never 
const METHODS = {
    a: () => "a" as const,
    b: () => "b" as const,
    c: () => "c" as const
}
function useMethods<T extends Permutation<MethodKey>>(keys: T) {
    return keys.filter((key): key is MethodKey => !!key)
               .map((key) => METHODS[key]) as GetMethodValue<T>
}
const [a, b] = useMethods(['a', 'b'])
const valueA = a()

感嘆

只是一個三行代碼就實現(xiàn)的簡單方法,但要做出準確的結(jié)果推導(dǎo)卻需要這么復(fù)雜的類型聲明去鋪墊,雖然最后寫出來很爽,但也感嘆作為庫開發(fā)者的一方真是非常不容易,這當中為了類型推導(dǎo),還增加了冗余的代碼,為了支持元組的可選值,不得不將變量打為可選,從而需要先 filtermap 才能保證結(jié)果不會出現(xiàn)空值的類型推導(dǎo)。

身為一個前端,在寫 Ts 時時不時就要為幾個簡單結(jié)果的推導(dǎo)準確性花上小半天時間,有時候也覺得很不值得,不知道其他語言在類型上是否也有類似的煩惱,也希望 Typescript 團隊能有更好的類型推斷手段演進。

本文最后的解決方案不一定為最佳解決方案,不過作者也在社區(qū)和搜索網(wǎng)站上檢索過答案,最后也沒找到滿意的解答,更多關(guān)于Typescript類型推導(dǎo)代碼函數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • TypeScript類型級別和值級別示例詳解

    TypeScript類型級別和值級別示例詳解

    這篇文章主要為大家介紹了TypeScript類型級別和值級別示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • typescript 支持與本地調(diào)試配置詳解

    typescript 支持與本地調(diào)試配置詳解

    這篇文章主要為大家介紹了typescript 支持與本地調(diào)試配置詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • Nest框架中集成使用Swagger示例說明

    Nest框架中集成使用Swagger示例說明

    這篇文章主要為大家介紹了Nest框架中集成使用Swagger的示例說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • TypeScript防抖節(jié)流函數(shù)示例詳解

    TypeScript防抖節(jié)流函數(shù)示例詳解

    這篇文章主要為大家介紹了TypeScript防抖節(jié)流函數(shù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • 數(shù)據(jù)結(jié)構(gòu)Typescript之哈希表實現(xiàn)詳解

    數(shù)據(jù)結(jié)構(gòu)Typescript之哈希表實現(xiàn)詳解

    這篇文章主要為大家介紹了數(shù)據(jù)結(jié)構(gòu)Typescript之哈希表實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • 簡單三行代碼函數(shù)實現(xiàn)幾十行Typescript類型推導(dǎo)

    簡單三行代碼函數(shù)實現(xiàn)幾十行Typescript類型推導(dǎo)

    這篇文章主要為大家介紹了簡單三行代碼函數(shù)實現(xiàn)幾十行Typescript類型推導(dǎo)的方案示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • Typescript tsconfig.json的配置詳情

    Typescript tsconfig.json的配置詳情

    這篇文章主要為大家介紹了Typescript tsconfig.json的配置詳情示例 ,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • typescript快速上手的基礎(chǔ)知識篇

    typescript快速上手的基礎(chǔ)知識篇

    靜態(tài)類型的typescript與傳統(tǒng)動態(tài)弱類型語言javascript不同,在執(zhí)行前會先編譯成javascript,因為它強大的type類型系統(tǒng)加持,能讓我們在編寫代碼時增加更多嚴謹?shù)南拗?。注意,它并不是一門全新的語言,所以并沒有增加額外的學(xué)習成本
    2022-12-12
  • 詳解什么是TypeScript里的Constructor?signature

    詳解什么是TypeScript里的Constructor?signature

    這篇文章主要介紹了什么是TypeScript里的Constructor?signature詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • Typescript裝飾器AOP示例詳解

    Typescript裝飾器AOP示例詳解

    這篇文章主要為大家介紹了Typescript裝飾器AOP示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12

最新評論

丹巴县| 临沭县| 重庆市| 楚雄市| 德清县| 玉林市| 金昌市| 滨海县| 莱阳市| 江川县| 都匀市| 波密县| 墨竹工卡县| 海淀区| 嘉荫县| 平舆县| 资兴市| 湖北省| 舒城县| 田林县| 龙泉市| 松原市| 喀什市| 甘肃省| 汶川县| 遂川县| 潮州市| 九江县| 清丰县| 泰宁县| 奉化市| 崇州市| 潍坊市| 米林县| 桂平市| 桃园市| 德惠市| 陵水| 开平市| 承德县| 彭州市|