<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>

          7個Typescript常見錯誤需要你注意避免發(fā)生

          共 7610字,需瀏覽 16分鐘

           ·

          2021-08-10 14:43

          英文 | https://betterprogramming.pub/7-typescript-common-mistakes-to-avoid-581c30e514d6

          翻譯 | 楊小二


          自 2012 年 10 月首次出現(xiàn)以來,TypeScript 獲得了廣泛的關注,它已成為 Web 開發(fā)領域真正的游戲規(guī)則改變者。盡管如此,有些人一直對使用它持懷疑態(tài)度。
          將 TypeScript 添加到項目時,開發(fā)人員應該接受它而不是反對它,這一點很重要。
          這可能會使你沮喪,以及在開發(fā)中TypeScript 會成為開發(fā)過程中的瓶頸。
          但是,如果使用得當,擁有可讀且易于維護的代碼庫就變得至關重要。
          它具有強大的功能,例如映射類型、重載、類型推斷、可選類型等,并且隨著增量升級,這些功能每天都在變得更好。
          為什么有些人會覺得 TypeScript 正在損害他們的生產(chǎn)力?我們怎樣才能防止這種不好情況的發(fā)生?是否有一些我們可以采用的最佳實踐做法?
          在這里,我們將討論使用 TypeScript 時最常見的錯誤。通過不迷戀這些常見的問題,我們將看到我們的生產(chǎn)力和代碼可維護性的提高。
          現(xiàn)在開始吧。
          1、不啟用嚴格模式
          如果沒有打開 TypeScript 嚴格模式,類型可能會過于松散,這將使我們的代碼庫類型安全性降低。它會給人錯誤的印象,因為有些人認為通過添加 TypeScript,所有TypeScript問題都會自動修復。
          以后,我們將成為這些類型的受害者。我們最終可能會用補丁修復它們,而不是修復根本原因。這可能會導致你認為該工具做得不好。
          我們?nèi)绾螁⒂脟栏衲J剑克ㄟ^在 tsconfig.json 文件中將 strict 參數(shù)設置為 true 來啟用,如下所示:
          {  ...  "compilerOptions": {    "strict": true,    ...  },  ...}

          啟用strict模式將在鉤子下啟用:

          noImplicitAny:此標志可防止我們使用推斷的 any 公開合約。如果我們不指定類型并且無法推斷,則默認為any。

          noImplicitThis:它將防止 this 關鍵字的不必要的不安全用法。防止不需要的行為將使我們免于一些調(diào)試麻煩,如下所示:

          class Book {  pages: number;  constructor(totalPages: number) {    this.pages = totalPages;  }
          isLastPageFunction() { return function (currentPage: number) { // ? 'this' here implicitly has type 'any' because it does not have a type annotation. return this.pages === currentPage; } }}

          alwaysStrict:這將確保在我們所有轉(zhuǎn)換后的 JavaScript 文件中發(fā)出 use strict ,但編譯器除外。這將提示 JavaScript 引擎代碼應該在嚴格模式下執(zhí)行。

          strictBindCallApply:這將確保我們使用正確的參數(shù)調(diào)用 call 、 bind 和 apply 函數(shù)。讓我們看一個例子:

          const logNumber = (x: number) => {  console.log(`number ${x} logged!`)}
          // ? works finelogNumber.call(undefined, 10);
          // ? error: Argument of type 'string' is not assignable to parameter of type 'number'.ts(2345)logNumber.call(undefined, "10");

          strictNullChecks:如果此標志關閉,則編譯器會有效地忽略 undefined、null 和 false。松散的輸入可能會導致運行時出現(xiàn)意外錯誤。讓我們看一個例子:

          interface Person {  name: string | undefined;  age: number;}
          const x: Person = { name: 'Max', age: 3 };
          // ? Works with strictNullChecks off, which is laxconsole.log(x.name.toLowerCase());

          // ? Fails with strictNullChecks on as x.name could be undefinedconsole.log(x.name.toLowerCase());

          strictFunctionTypes:啟用此標志可確保更徹底地檢查函數(shù)參數(shù)。

          strictPropertyInitialization:當設置為 true 時,這將強制我們在構(gòu)造函數(shù)中設置所有屬性值。

          正如所見,TypeScript 的嚴格變量是上述所有標志的簡寫。我們可以通過使用嚴格或逐步啟用它們來啟用它們。

          更嚴格的類型將幫助我們在編譯時捕獲更多錯誤。

          2、重新聲明接口

          在鍵入組件接口時,通常需要具有相同類型的一些不同接口變體。這些可以在一兩個參數(shù)中變化。一個常見的錯誤是手動重新定義這些變體。這將導致:

          • 不必要的樣板。

          • 需要多次更改。如果一個屬性在一個地方發(fā)生變化,則需要將該更改傳播到多個文件。

          很久以前,TypeScript 發(fā)布了一個旨在解決此目的的功能:映射類型。它們讓我們可以根據(jù)我們定義的一些規(guī)則,在現(xiàn)有類型的基礎上創(chuàng)建新類型。這確實會導致更具可讀性和聲明性的代碼庫。

          讓我們看一個例子:

          interface Book {  author?: string;  numPages: number;  price: number;}
          // ? Article is a Book without a Pagetype Article = Omit<Book, 'numPages'>;
          // ? We might need a readonly verison of the Book Typetype ReadonlyBook = Readonly<Book>;
          // ? A Book that must have an authortype NonAnonymousBook = Omit<Book, 'author'> & Required<Pick<Book, 'author'>>;

          在上面的代碼中,我們保留了一個單一的事實來源:Book 實體。它的所有變體都使用映射類型功能來表達,這大大減少了對代碼進行類型化和維護的成本。

          映射類型也可以應用于聯(lián)合,如下所示:

          type animals = 'bird' | 'cat' | 'crocodile';
          type mamals = Exclude<animals, 'crocodile'>;// 'bird' | 'cat'

          TypeScript 附帶以下映射類型:Omit、Partial、Readonly、Exclude、Extract、NonNullable、ReturnType。

          我們可以創(chuàng)建自己的實用程序并在我們的代碼庫中重用它們。

          3、不依賴類型推斷

          TypeScript 推理是這種編程語言最強大的工具之一。它為我們完成所有工作。我們只需要確保在盡可能少的干預下將所有部分加在一起。

          實現(xiàn)這一目標的一個關鍵操作符是 typeof。它是一個類似于 JavaScript 的運算符。它不會返回 JavaScript 類型,而是返回 TypeScript 類型。使用這個操作數(shù)可以避免我們重新聲明相同的類型。

          讓我們通過一個例子來看看:

          const addNumber = (a: number, b: number) => a + b;
          // ? you are hardcoding the type `number` instead of relying on what the function returnsconst processResult = (result: number) => console.log(result);processResult(addNumber(1, 1));

          // ? result will be whatever the return type of addNumber function// no need for us to redefine itconst processResult = (result: ReturnType<typeof addNumber>) => console.log(result);processResult(addNumber(1, 1));

          在上面的代碼中,注意結(jié)果參數(shù)類型。最好依賴 ReturnType<typeof addNumber> 而不是添加數(shù)字類型。通過對數(shù)字類型進行硬編碼,我們完成了編譯器的工作。

          最好使用適當?shù)恼Z法來表達我們的類型。TypeScript 將為我們完成繁重的工作。

          讓我們看一個虛擬示例:

          // ? Sometimes for one of objects it is not necessary to define// interfaces for itinterface Book {  name: string,  author: string}
          const book: Book = { name: 'For whom the bell tolls', author: 'Hemingway'}
          const printBook = (bookInstance: Book) => console.log(bookInstance)

          請注意,Book 接口用于特定場景,甚至不需要創(chuàng)建接口。

          通過依賴 TypeScript 的推理,代碼變得不那么雜亂,更易于閱讀。下面是一個例子:

          // ? For simple scenarios we can rely on type inferenceconst book = {  name: 'For whom the bell tolls',  author: 'Hemingway'}
          const printBook = (bookInstance: typeof book) => console.log(bookInstance)

          TypeScript 甚至有 infer 運算符,它可以與 Mapped Types 結(jié)合使用以從另一個類型中提取一個類型。

          const array: number[] = [1,2,3,4];
          // ? type X will be numbertype X = typeof array extends (infer U)[] ? U : never;

          在上面的例子中,我們可以看到如何提取數(shù)組的類型。

          4、不正確的使用 Overloading

          TypeScript 本身支持重載。這很好,因為它可以提高我們的可讀性。但是,它不同于其他類型的重載語言。

          在某些情況下,它可能會使我們的代碼更加復雜和冗長。為了防止這種情況發(fā)生,我們需要牢記兩條規(guī)則:

          1. 避免編寫多個僅尾隨參數(shù)不同的重載

          // ? instead of thisinterface Example {  foo(one: number): number;  foo(one: number, two: number): number;  foo(one: number, two: number, three: number): number;}
          // ? do thisinterface Example { foo(one?: number, two?: number, three?: number): number;}

          你可以看到兩個接口是如何相等的,但第一個比第二個更冗長。在這種情況下最好使用可選參數(shù)。

          2. 避免僅在一種參數(shù)類型中編寫因類型不同而不同的重載

          // ? instead of thisinterface Example {  foo(one: number): number;  foo(one: number | string): number;}
          // ? do thisinterface Example { foo(one: number | string): number;}

          與前面的示例一樣,第一個界面變得非常冗長。最好使用聯(lián)合來代替。

          5、使用函數(shù)類型

          TypeScript 附帶 Function 類型。這就像使用 any 關鍵字但僅用于函數(shù)。遺憾的是,啟用嚴格模式不會阻止我們使用它。

          這里有一點關于函數(shù)類型:

          • 它接受任意數(shù)量和類型的參數(shù)。

          • 返回類型始終為 any。

          讓我們看一個例子:

          // ? Avoid, parameters types and length are unknown. Return type is anyconst onSubmit = (callback: Function) => callback(1, 2, 3);
          // ? Preferred, the arguments and return type of callback is now clearconst onSubmit = (callback: () => Promise<unknown>) => callback();

          在上面的代碼中,通過使用顯式函數(shù)定義,我們的回調(diào)函數(shù)更具可讀性和類型安全性。

          6、依賴第三方實現(xiàn)不變性

          在使用函數(shù)式編程范式時,TypeScript 可以提供很大幫助。它提供了所有必要的工具來確保我們不會改變我們的對象。我們不需要在我們的代碼庫中添加像 ImmutableJS這樣的笨重的庫。

          讓我們通過以下示例來看看我們可以使用的一些工具:

          // ? declare properties as readonlyinterface Person {  readonly name: string;  readonly age: number;}
          // ? implicitely declaring a readonly arraysconst x = [1,2,3,4,5] as const;
          // ? explicitely declaring a readonly arrayconst y: ReadonlyArray<{ x: number, y: number}> = [ {x: 1, y: 1}]
          interface Address { street: string; city: string;}
          // ? converting all the type properties to readonlytype ReadonlyAddress = Readonly<Address>;

          正如你從上面的例子中看到的,我們有很多工具來保護我們的對象免于變異。

          通過使用內(nèi)置功能,我們將保持我們的 bundle light 和我們的類型一致。

          7、不理解 infer/never 關鍵字

          infer 和 never 關鍵字很方便,可以在許多情況下提供幫助,例如:

          推斷

          使用 infer 關鍵字就像告訴 TypeScript,“我想把你在這個位置推斷出來的任何東西分配給一個新的類型變量。”

          我們來看一個例子:

          const array: number[] = [1,2,3,4];
          type X = typeof array extends (infer U)[] ? U : never;

          在上面的代碼中,作為array extends infer U[],X變量將等于 a Number。

          never

          該never類型表示值是不會發(fā)生的類型。

          我們來看一個例子:

          interface HttpResponse<T, V> {  data: T;  included?: V;}
          type StringHttpResponse = HttpResponse<string, never>;
          // ? included prop is not assignableconst fails: StringHttpResponse = { data: 'test', included: {} // ^^^^^ // Type '{}' is not assignable to type 'never'}
          // ? included is not assignedconst works: StringHttpResponse = { data: 'test',}

          在上面的代碼中,我們可以使用 never 類型來表示我們不希望某個屬性是可賦值的。

          我們可以將 Omit Mapped 類型用于相同的目的:

          type StringHttpResponse = Omit<HttpResponse<string, unkown>, 'included'>;

          但是,你可以看到它的缺點。它更冗長。如果你檢查 Omit 的內(nèi)部結(jié)構(gòu),它會使用 Exclude,而后者又使用 never 類型。

          通過依賴 infer 和 never 關鍵字,我們省去了復制任何類型的麻煩,并更好地表達我們的接口。

          總結(jié)

          這些指南易于遵循,旨在幫助你接受 TypeScript,而不是與之抗爭。TypeScript 旨在幫助你構(gòu)建更好的代碼庫,而不是妨礙你。

          通過應用這些簡單的技巧,你將擁有一個更好、更簡潔且易于維護的代碼庫。

          我們是否遺漏了你項目中經(jīng)常發(fā)生的任何常見錯誤?請在評論中與我分享它們。

          感謝你的閱讀。

          學習更多技能

          請點擊下方公眾號

          瀏覽 22
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  亚洲无码第一页 | 亚洲成人高清在线观看 | 色网中文字幕 | 吖v在线视频免费观看免费观看 | 又大又粗又硬免费视频 |