<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          聊一聊你為什么你不適應(yīng) TypeScript

          共 4704字,需瀏覽 10分鐘

           ·

          2023-07-27 11:00

          前言

          在群里看到一些問題和言論:為什么你們這么喜歡“類型體操”?為什么我根本學(xué)不下去 TypeScript?我最討厭那些做類型體操的了;為什么我學(xué)了沒過多久馬上又忘了?

          有感于這些問題,我想從最簡(jiǎn)單的一個(gè)角度來切入介紹一下 TypeScript,并向大家介紹并不是只要是個(gè)類型運(yùn)算就是體操。并在文中介紹一種基本思想作為你使用類型系統(tǒng)的基本指引。

          引子

          我將從一個(gè)相對(duì)簡(jiǎn)單的 API 的設(shè)計(jì)過程中闡述關(guān)于類型的故事。在這里我們可以假設(shè)我們現(xiàn)在是一個(gè)工具的開發(fā)者,然后我們需要設(shè)計(jì)一個(gè) API 用于從對(duì)象中拿取指定的一些 key 作為一個(gè)新的對(duì)象返回給外面使用。

          垃圾 TypeScript

          一個(gè)人說:我才不用什么破類型,我寫代碼就是要沒有類型,我就是要隨心所欲的寫。然后寫下了這段代碼。

          declare function pick(target: any, ...keys: any): any

          他的用戶默默的寫下了這段代碼:

          pick(undefined'a'1).b

          寫完運(yùn)行,發(fā)現(xiàn)問題大條了,控制臺(tái)一堆報(bào)錯(cuò),接口數(shù)據(jù)也提交不上去了,怎么辦呢?

          剛學(xué) TypeScript

          一個(gè)人說:稍微檢查一下傳入類型就好了,別讓人給我亂傳參數(shù)就行。

          declare function pick(target: Record<string, unknown>, ...keys: string[]): unknown

          很好,上面的問題便不復(fù)存在了,API 也是基本可用的了。但是!當(dāng)對(duì)象復(fù)雜的時(shí)候,以及字段并不是短單詞長(zhǎng)度的時(shí)候就會(huì)發(fā)現(xiàn)了一個(gè)沒解決的問題。

          pick({ abcdefghijkl: '123' }, 'abcdefghikjl')

          從肉眼角度上,我們很難發(fā)現(xiàn)這前后的不一致,所以我們?yōu)槭裁匆屨{(diào)用方的用戶自己去 check 自己的字段有沒有寫對(duì)呢?

          不就 TypeScript

          一個(gè)人說:這還不簡(jiǎn)單,用個(gè)泛型加 keyof 不就行了。

          declare function pick<
            T extends Record<stringunknown>
          >(target: T, ...keys: (keyof T)[]): unknown

          我們又進(jìn)一步解決的上面的問題,但是!還是有著相似的問題,雖然我們不用檢查 keys 是不是傳入的是一個(gè)正確的值了,但是我們實(shí)際上對(duì)返回的值也存在一個(gè)類似的問題。

          pick({ abcdefghijkl: '123' }, 'abcdefghijkl').abcdefghikjl
          • 一點(diǎn)小小的拓展

            在這里我們看起來似乎是一個(gè)很簡(jiǎn)單的功能,但實(shí)際上蘊(yùn)含著一個(gè)比較重要的信息。

            為什么我們之前的方式都拿不到用戶傳入進(jìn)來的類型信息呢?是有原因的,當(dāng)我們?cè)O(shè)計(jì)的 API 的時(shí)候,前面的角度是從,如何校驗(yàn)類型方向進(jìn)行的思考。

            而這里是嘗試去通過約定好的一種規(guī)則,通過 TypeScript 的隱式類型推斷獲得到傳入的類型,再通過約定的規(guī)則轉(zhuǎn)化出一種新的類型約束來對(duì)用戶的輸入進(jìn)行限制。

          算算 TypeScript

          一個(gè)人說:好辦,算出來一個(gè)新的類型就好了。

          declare function pick<
            T extends Record<stringunknown>,
            Keys extends keyof T
          >(target: T, ...keys: Keys[]): 
          {
            [K in Keys]: T[K]
          }

          到這里已經(jīng)是對(duì)類型的作用有了基礎(chǔ)的了解了,能寫出來符合開發(fā)者所能接受的類型相對(duì)友好的代碼了。我們可以再來思考一些更特殊的情況:

          // 輸入了重復(fù)的 key
          pick({ a: '' }, 'a''a')

          完美 TypeScript

          到這里,我們便是初步開始了類型“體操”。但是在本篇里,我們不去分析它。

          export type L2T<L, LAlias = L, LAlias2 = L> = [L] extends [never]
            ? []
            : L extends infer LItem
              ? [LItem?, ...L2T<Exclude<LAlias2, LItem>, LAlias>]
              : never

          declare function pick<
            T extends Record<stringunknown>,
            Keys extends L2T<keyof T>
          >(target: T, ...keys: Keys): Pick<TKeys[number] & keyof T>

          const x0 = pick({ a: '1', b: '2' }, 'a')
          console.log(x0.a)
          // @ts-expect-error
          console.log(x0.b)

          const x1 = pick({ a: '1', b: '2' }, 'a', 'a')
          //                                  ^^^^^^^^
          // TS2345Argument of type '["a", "a"]' is not assignable to parameter of type '["a"?, "b"?] | ["b"?, "a"?]'.
          //   Type '["a", "a"]' is not assignable to type '["a"?, "b"?]'.
          //     Type at position 1 in source is not compatible with type at position 1 in target.
          //       Type '"a"' is not assignable to type '"b"'.

          一個(gè)相對(duì)來說比較完美的 pick 函數(shù)便完成了。

          總結(jié)

          我們?cè)賮砘氐轿覀兊臉?biāo)題吧,從我對(duì)大多數(shù)人的觀察來說,很多的人開始來使用 TypeScript 有幾種原因:

          • 看到大佬們都在玩,所以自己也想來“玩”,然后為了過類型校驗(yàn)而去寫
          • 看到一些成熟的項(xiàng)目在使用 TypeScript ,想?yún)⑴c貢獻(xiàn),參與過程中為了讓類型通過而想辦法去解決類型報(bào)錯(cuò)
          • 公司整體技術(shù)棧采用的是 TypeScript ,要用 TypeScript 進(jìn)行業(yè)務(wù)編寫,從而為了過類型檢查和 review 而去解決類型問題

          諸如此類的問題還有很多,我將這種都劃分為「為了解決類型檢查的問題」而進(jìn)行的類型編程,這也是大多數(shù)人為什么非常不適應(yīng) TypeScript,甚至不喜歡他的一個(gè)原因。這其實(shí)對(duì)學(xué)習(xí) TypeScript 并不是一個(gè)很好的思路,在這里我覺得我們需要站在設(shè)計(jì)者的角度去對(duì)類型系統(tǒng)進(jìn)行思考。我覺得有以下幾個(gè)角度:

          • 類型檢查到位
          • 類型提示友好
          • 類型檢查嚴(yán)格
          • 擴(kuò)展性十足

          我們?nèi)绻驹谶@幾個(gè)角度對(duì)我們的 API 進(jìn)行設(shè)計(jì),我們可以發(fā)現(xiàn),開發(fā)者能夠很輕松的將他們需要的代碼編寫出來,而盡量不用去翻閱文檔,查找 example。

          希望通過我的這篇分享,大家能對(duì) TypeScript 多一些理解,并參與到生態(tài)中來,守護(hù)我們的 JavaScript。

          作者:一介4188

          https://juejin.cn/post/7248599585751515173

          瀏覽 83
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产欧美一区二区 | 亚洲A免费 | 日韩无码毛片 | 亚洲小早川无码在线播放 | 亚洲一区二区三区无码 |