TS保姆級教程,吐血整理常見問題

2022年10月23日15:44:00 熱門 1740

前言

  • 用 React 全家桶 + TS 寫項目快一年了,大大小小的坑踩了很多,在此整理了在項目中遇到的疑惑和問題。
  • 體會:不要畏懼 TS,別看 TS 官方文檔內容很多,其實在項目中常用的都是比較基礎的東西,像泛型運用、一些高級類型這種用的很少(封裝庫、工具函數、UI組件時用的比較多)。只要把常用的東西看熟,最多一個小時就能上手 TS。如果本文對你有所幫助,還請點個贊,謝謝啦~~
  • 如果大家想參考下整個開源的實踐的項目,vue3+ts的vban-admin react和ts的可以參考datart。
  • 什麼是 TypeScript

    一起養成寫作習慣!這是我參與「掘金日新計劃 · 4 月更文挑戰」的第21天,點擊查看活動詳情。

    typeScript,簡稱 ts,是微軟開發的一種靜態的編程語言,它是 JavaScript 的超集。 那麼它有什麼特別之處呢?

    1. 簡單來說,js 有的 ts 都有,所有js 代碼都可以在 ts 裡面運行。
    2. ts 支持類型支持,ts = type +JavaScript。

    那麼 ts 和 js 有什麼區別呢?

    JavaScript 屬於動態編程語言,而ts 屬於靜態編程語言。

    • js:邊解釋邊執行,錯誤只有在運行的時候才能發現
    • ts:先編譯再執行,在寫的時候就會發現錯誤了(ts不能直接執行,需要先編譯成 js )

    ts 完全支持 js ,可以直接轉換


    TS保姆級教程,吐血整理常見問題 - 天天要聞

    簡單的去理解

    JS 有的, TS 都有, JS 沒有的, TS 也有,畢竟 TS 是 JS 的超集嘛。

    TS 的缺點:

    • 不能被瀏覽器理解,需要被編譯成 JS
    • 有學習成本,寫習慣了 JS 的我們,要上手需要花時間去理解,而且 TS 中有一些概念還是有點難,比如泛型。

    什麼是類型註解?

    就是給變量添加類型約束,可以顯示標記出代碼中的意外行為,從而降低了發生錯誤的可能性 語法:

    let 變量名: 類型 = 初始值
    let age: number = 18

    這樣寫有啥好處呢?更好地規定了數據的類型,避免了不必要的錯誤。 如果你不小心寫錯了,他會直接提示你類型錯誤哦。是不是很貼心呢?

    比如:

    let a:number = '1'  

    代碼中的 : number 就是類型註解

    這個時候是時候介紹下ts的數據基本類型

        //字符串
        let str: string = "Domesy"
        
        // 數字
        let num: number = 7
        
        //布爾
        let bool: boolean = true
        
        //symbol
        let sym: symbol = symbol();
         
        //bigint
        let big: bigint = 10n
            
        //null
        let nu: null = null
        
        //undefined
        let un: undefined = undefined
    

    需要注意:

    • nullundefined 兩個類型一旦賦值上,就不能再賦值給任何其他類型
    • symbol是獨一無二的,假設再定義一個 sym1,那麼sym === sym1 為 false

    引用類型

    Array

    兩種方式:

    • 類型名稱 + []
    • Array<數據類型>
        let arr1: number[] = [1, 2, 3]
        
        let arr2: Array<number> = [1, 2, 3]
        
        let arr2: Array<number> = [1, 2, '3'] // error
        
         //要想是數字類型或字符串類型,需要使用 |
        let arr3: Array<number | string> = [1, 2, '3'] //ok

    Tuple(元組)

    Tuple 可以說是 Array 的一種特殊情況,針對上面的 arr3,我們看他的類型可以是string也可以是number,但對每個元素沒有作出具體的限制。

    那麼 Tuple 的作用就是限制元素的類型並且限制個數的數組,同時 Tuple這個概念值存在於TS,在JS上是不存在的

    這裡存在一個問題:在TS中,是允許對 Tuple 擴增的(也就是允許使用 push方法),但在訪問上不允許

        let t: [number, string] = [1, '2'] // ok
        let t1: [number, string] = [1, 3] // error
        let t2: [number, string] = [1] // error
        let t3: [number, string] = [1, '1', true] // error
    
    
        let t5: [number, string] = [1, '2'] // ok
        t.push(2)
        console.log(t) // [1, '2', 2]
    
        let a =  t[0] // ok
        let b = t[1] // ok
        let c = t[2] // error

    另外還有object 和定義函數;

    元祖越界問題

    let aaa: [string, number] = ['aaa', 5];
    // 添加時不會報錯
    aaa.push(6);
    // 打印整個元祖不會報錯
    console.log(aaa); // ['aaa',5,6];
    // 打印添加的元素時會報錯
    console.log(aaa[2]); // error

    什麼是函數類型接口

    • 對方法傳入的參數和返回值進行約束
    // 注意區別
    
    // 普通的接口
    interface discount1{
      getNum : (price:number) => number
    }
    
    // 函數類型接口
    interface discount2{
      // 注意:
      // “:” 前面的是函數的簽名,用來約束函數的參數
      // ":" 後面的用來約束函數的返回值
      (price:number):number
    }
    let cost:discount2 = function(price:number):number{
       return price * .8;
    }
    
    // 也可以使用類型別名
    type Add = (x: number, y: number) => number
    let add: Add = (a: number, b: number) => a + b

    什麼是類類型接口

    • 如果接口用於一個類的話,那麼接口會表示“行為的抽象”
    • 對類的約束,讓類去實現接口,類可以實現多個接口
    • 接口只能約束類的公有成員(實例屬性/方法),無法約束私有成員、構造函數、靜態屬性/方法
    // 接口可以在面向對象編程中表示為行為的抽象
    interface Speakable {
        name: string;
      
     		// ":" 前面的是函數簽名,用來約束函數的參數
        // ":" 後面的用來約束函數的返回值
        speak(words: string): void
    }
    
    interface Speakable2 {
        age: number;
    }
    
    class Dog implements Speakable, Speakable2 {
        name!: string;
        age = 18;
    
        speak(words: string) {
            console.log(words);
        }
    }
    
    let dog = new Dog();
    dog.speak('汪汪汪');

    什麼是混合類型接口

    • 一個對象可以同時做為函數和對象使用
    interface FnType {
        (getName:string):string;
    }
    
    interface MixedType extends FnType{
        name:string;
        age:number;
    }
    interface Counter {
        (start: number): string;
        interval: number;
        reset(): void;
    }
    
    function getCounter(): Counter {
        let counter = <Counter>function (start: number) { };
        counter.interval = 123;
        counter.reset = function () { };
        return counter;
    }
    
    let c = getCounter();
    c(10);
    c.reset();
    c.interval = 5.0;

    繼承 vs 多態

    • 繼承:子類繼承父類,子類除了擁有父類的所有特性外,還有一些更具體的特性
    • 多態:由繼承而產生了相關的不同的類,對同一個方法可以有不同的響應

    這個如果有學過Java的 就非常容易理解,我是之前做Java開發的。

    比如:

    class Animal {
        speak(word: string): string {
            return 'Animal: ' + word;
        }
    }
    
    class Cat extends Animal {
        speak(word: string): string {
            return 'Cat:' + word;
        }
    }
    
    class Dog extends Animal {
        speak(word: string): string {
            return 'Dog:' + word;
        }
    }
    
    let cat = new Cat();
    console.log(cat.speak('hello'));
    let dog = new Dog();
    console.log(dog.speak('hello'));

    什麼是可選鏈運算符的使用

    • 可選鏈運算符是一種先檢查屬性是否存在,再嘗試訪問該屬性的運算符,其符號為 ?.
    • 如果運算符左側的操作數 ?. 計算為 undefined 或 null,則表達式求值為 undefined 。否則,正常觸發目標屬性訪問、方法或函數調用。
    • 可選鏈運算符處於 stage3 階段,使用 @babel/plugin-proposal-optional-chaining 插件可以提前使用,TS 3.7版本正式支持使用,以前的版本會報錯
    a?.b;
    // 相當於 a == null ? undefined : a.b;
    // 如果 a 是 null/undefined,那麼返回 undefined,否則返回 a.b 的值.
    
    a?.[x];
    // 相當於 a == null ? undefined : a[x];
    // 如果 a 是 null/undefined,那麼返回 undefined,否則返回 a[x] 的值
    
    a?.b();
    // 相當於a == null ? undefined : a.b();
    // 如果 a 是 null/undefined,那麼返回 undefined
    // 如果 a.b 不是函數的話,會拋類型錯誤異常,否則計算 a.b() 的結果

    什麼是擴展全局變量的類型

    interface String {
        // 這裡是擴展,不是覆蓋,所以放心使用
        double(): string;
    }
    
    String.prototype.double = function () {
        return this + '+' + this;
    };
    console.log('hello'.double());
    
    // 如果加了這個,就會報錯
    // export {}
    

    如何編寫 react + ts 版的 HOC

    interface Greeting {
        name: string;
        age: number;
    }
    
    const Hello:React.FC<Greeting> = (props) => <h1>Hello {props.name}</h1>;
    // 推薦使用第二種
    const Hello2 = (props:Greeting) => <h1>Hello {props.name}</h1>;
    

    函數賦值

    JS 中變量隨便賦值沒問題,

    但在 TS 中函數不能隨便賦值,會報錯的,

    TS 進階

    這一部分的內容就需要費點腦細胞了,畢竟學習一門語言,還是沒那麼容易的,最好把基礎的內容都理解透徹之後再來學進階。

    主要要掌握聯合類型,交叉類型,類型別名,類型保護,類型斷言
    抽象類,多態,條件類型等

    總結:

    我之前學習 TS,是死磕 TS 文檔,非常枯燥,上手難度大,學習效率很低,而且學了就忘。

    後來我才發現,我們不一定需要學習那麼多知識,能上手就行,TS 的文檔比較適合入門之後查閱用,而不適合初學者用。基礎類型 · TypeScript中文網 · TypeScript——JavaScript的超集

    很多對 TS 學習得很深的人,甚至還在做 TS 類型體操,把 TS 像 LeetCode 一樣刷,作為一個搬磚人,真的沒必要去跟風,畢竟應付日常增刪改查不需要學那麼深。

    我的理念一直是,用到了再去學,不要焦慮,人精力有限。比如當我需要去理解 Vue3 的源碼或者設計一個庫的時候,目前的 TS 知識儲備不夠了,再去做做類型體操,也不遲。

    最近重學一次 TS,查閱了很多相對官方文檔更通俗易懂的教程,總結了學習中的重點,形成了本文。

    熱門分類資訊推薦

    曾小賢的上司Lisa榕,現實中不僅才貌雙全,還嫁給了CEO - 天天要聞

    曾小賢的上司Lisa榕,現實中不僅才貌雙全,還嫁給了CEO

    曾小賢的上司Lisa榕,現實中不僅才貌雙全,還嫁給了CEO雖然說《愛情公寓》這部劇在劇情上充滿了爭議,但是一定程度上,這部劇也是很多人的回憶,是伴隨了一代人的青春回憶,而且劇中的很多角色都成為了經典,他們的口頭禪也一直被拿來玩兒梗。
    Lisa榕做主持多年沒紅,被陳赫拉進愛情公寓爆紅,如今怎樣了 - 天天要聞

    Lisa榕做主持多年沒紅,被陳赫拉進愛情公寓爆紅,如今怎樣了

    談到《愛情公寓》這部火爆一時的歡樂喜劇,大家肯定都不陌生。不知道大家是否還記得《愛情公寓》中那個把曾小賢治得服服帖帖的女上司Lisa榕,現實中的她名叫榕榕,和劇中的形象也判若兩人。1981年出生在遼寧瀋陽的榕榕,畢業於上海戲劇學院,後來成為了上海東方傳媒集團有限公司的一名主持人。