1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Typescript 高級技巧

        共 7657字,需瀏覽 16分鐘

         ·

        2021-09-11 14:28

        用了一段時間的 typescript 之后,深感中大型項目中 typescript 的必要性,它能夠提前在編譯期避免許多 bug,如很惡心的拼寫問題。而越來越多的 package 也開始使用 ts,學習 ts 已是勢在必行。

        以下是我在工作中總結到的比較實用的 typescript 技巧。

        01 keyof

        keyofObject.keys 略有相似,只不過 keyofinterface 的鍵。

        interface Point {
            x: number;
            y: number;
        }

        // type keys = "x" | "y"
        type keys = keyof Point;

        假設有一個 object 如下所示,我們需要使用 typescript 實現(xiàn)一個 get 函數(shù)來獲取它的屬性值

        const data = {
          a: 3,
          hello: 'world'
        }

        function get(o: object, name: string{
          return o[name]
        }

        我們剛開始可能會這么寫,不過它有很多缺點

        1. 無法確認返回類型:這將損失 ts 最大的類型校驗功能
        2. 無法對 key 做約束:可能會犯拼寫錯誤的問題

        這時可以使用 keyof 來加強 get 函數(shù)的類型功能,有興趣的同學可以看看 _.get 的 type 標記以及實現(xiàn)

        function get<T extends objectK extends keyof T>(o: T, name: K): T[K{
          return o[name]
        }

        02 Required & Partial & Pick

        既然了解了 keyof,可以使用它對屬性做一些擴展, 如實現(xiàn) PartialPick,Pick 一般用在 _.pick

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

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

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

        interface User {
          id: number;
          age: number;
          name: string;
        };

        // 相當于: type PartialUser = { id?: number; age?: number; name?: string; }
        type PartialUser = Partial<User>

        // 相當于: type PickUser = { id: number; age: number; }
        type PickUser = Pick<User, "id" | "age">

        這幾個類型已內置在 Typescript 中

        03 Condition Type

        類似于 js 中的 ?: 運算符,可以使用它擴展一些基本類型

        extends U ? X : Y

        type isTrue<T> = T extends true ? true : false
        // 相當于 type t = false
        type t = isTrue<number>

        // 相當于 type t = false
        type t1 = isTrue<false>

        04 never & Exclude & Omit

        官方文檔對 never 的描述如下

        the never type represents the type of values that never occur.

        結合 neverconditional type 可以推出很多有意思而且實用的類型,比如 Omit

        type Exclude<T, U> = T extends U ? never : T;

        // 相當于: type A = 'a'
        type A = Exclude<'x' | 'a''x' | 'y' | 'z'>

        結合 Exclude 可以推出 Omit 的寫法

        type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

        interface User {
          id: number;
          age: number;
          name: string;
        };

        // 相當于: type PickUser = { age: number; name: string; }
        type OmitUser = Omit<User, "id">

        05 typeof

        顧名思義,typeof 代表取某個值的 type,可以從以下示例來展示他們的用法

        const a: number = 3

        // 相當于: const b: number = 4
        const b: typeof a = 4

        在一個典型的服務端項目中,我們經常需要把一些工具塞到 context 中,如config,logger,db models, utils 等,此時就使用到 typeof。

        import logger from './logger'
        import utils from './utils'

        interface Context extends KoaContect {
          logger: typeof logger,
          utils: typeof utils
        }

        app.use((ctx: Context) => {
          ctx.logger.info('hello, world')

          // 會報錯,因為 logger.ts 中沒有暴露此方法,可以最大限度的避免拼寫錯誤
          ctx.loger.info('hello, world')
        })

        06 is

        在此之前,先看一個 koa 的錯誤處理流程,以下是對 error 進行集中處理,并且標識 code 的過程

        app.use(async (ctx, next) => {
          try {
            await next();
          } catch (err) {
            let code = 'BAD_REQUEST'
            if (err.isAxiosError) {
              code = `Axios-${err.code}`
            } else if (err instanceof Sequelize.BaseError) {

            }
            ctx.body = {
              code
            }
          }
        })

        err.code 處,會編譯出錯,提示 Property 'code' does not exist on type 'Error'.ts(2339)。

        此時可以使用 as AxiosError 或者 as any 來避免報錯,不過強制類型轉換也不夠友好

        if ((err as AxiosError).isAxiosError) {
          code = `Axios-${(err as AxiosError).code}`
        }

        此時可以使用 is 來判定值的類型

        function isAxiosError (error: any): error is AxiosError {
          return error.isAxiosError
        }

        if (isAxiosError(err)) {
          code = `Axios-${err.code}`
        }

        GraphQL 的源碼中,有很多諸如此類的用法,用以標識類型

        export function isType(typeany): type is GraphQLType;

        export function isScalarType(typeany): type is GraphQLScalarType;

        export function isObjectType(typeany): type is GraphQLObjectType;

        export function isInterfaceType(typeany): type is GraphQLInterfaceType;

        07 interface & type

        interfacetype 的區(qū)別是什么?可以參考以下 stackoverflow 的問題

        https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types

        一般來說,interfacetype 區(qū)別很小,比如以下兩種寫法差不多

        interface A {
          a: number;
          b: number;
        };

        type B = {
          a: number;
          b: number;
        }

        其中 interface 可以如下合并多個,而 type 只能使用 & 類進行連接。

        interface A {
            a: number;
        }

        interface A {
            b: number;
        }

        const a: A = {
            a: 3,
            b: 4
        }

        08 Record & Dictionary & Many

        這幾個語法糖是從 lodash 的 types 源碼中學到的,平時工作中的使用頻率還挺高。

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

        interface Dictionary<T> {
          [index: string]: T;
        };

        interface NumericDictionary<T> {
          [index: number]: T;
        };

        const data:Dictionary<number> = {
          a: 3,
          b: 4
        }

        09 使用 const enum 維護常量表

        相比使用字面量對象維護常量,const enum 可以提供更安全的類型檢查

        // 使用 object 維護常量
        const TODO_STATUS {
          TODO: 'TODO',
          DONE: 'DONE',
          DOING: 'DOING'
        }
        // 使用 const enum 維護常量
        const enum TODO_STATUS {
          TODO = 'TODO',
          DONE = 'DONE',
          DOING = 'DOING'
        }

        function todos (status: TODO_STATUS): Todo[];

        todos(TODO_STATUS.TODO)

        10 VS Code Tips & Typescript Command

        使用 VS Code 有時會出現(xiàn),使用 tsc 編譯時產生的問題與 vs code 提示的問題不一致

        找到項目右下角的 Typescript 字樣,右側顯示它的版本號,可以點擊選擇 Use Workspace Version,它表示與項目依賴的 typescript 版本一直。

        或者編輯 .vs-code/settings.json

        {
          "typescript.tsdk""node_modules/typescript/lib"
        }

        11 Typescript Roadmap

        最后一條也是最重要的一條,翻閱 Roadmap,了解 ts 的一些新的特性與 bug 修復情況。

        Typescript Roadmap

        參考

        • https://www.typescriptlang.org/docs/handbook/advanced-types.html
        • https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html
        • https://moin.world/2017/06/18/10-typescript-features-you-might-not-know/
        瀏覽 32
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产免费操逼视频 | 91精品xxxx瑜伽裤日本 | 黄色小短片 | 18禁成人福利网站视频播放 | 成人做爰高潮片免费看三区 | 亚洲婷婷女色 | 国产精品一区二区三区不卡 | hd欧美free性xxxx护土 | 九九久久久久久 | 快色网站 |