深入 TypeScript – 2( 幾個常用的小技巧)

Pandaaa發表於2019-03-02

寫在最前面

  • 剛開始寫 typescript 遇到的問題和簡單的解決方案。

Q&A

1、是否所有變數都需要做型別註解?

  • 這個分情況,原則上來說,我們希望能對所有的值都做型別註解。

  • 對於TS編譯器來說,如果宣告變數時沒有做型別註解,那麼TS會根據賦值自動推匯出變數型別。這一點大多數情況下很完美,很方便,但是有一些列外:

  • 後面賦值不同型別的值
    當你後面需要重新對該變數賦值其他型別時,那麼TS會給出錯誤,因為與TS初始推匯出的型別不一致了。

let a = 1;
a= `string`; // error!
 

let obj = {
    name: `John`
}
obj.age = 20; // error!
obj.name = 250; // error!
 
 
// better
let a: string | number = 1;
a = `string`; // ok
 
 
let obj: {
    name: string | number;
    age?: number;
} = {
    name: `John`
}
obj.age = 20; // ok
obj.name = 250; // ok

複製程式碼

初始賦值時不是明確的值
即該值當前TS並不知道其型別,比如來自於後端介面返回的值、其他為明確宣告型別的函式返回等。即沒有初始化或者TS無法根據初始化值推匯出型別,則會預設為any型別。

2、在對介面的時候我們定義介面的引數值

  • 其實這種情況下不會報錯,但是這樣子會丟失型別檢查和程式碼提示功能。所以這種情況,最好可以新增型別宣告和註解。
// normal
http.get(`/api`)
    .then(resp => {
        let data = resp; // data: any
    });
 
 
// good one
interface IResponse {
    code: number;
    data: IUser;
}
 
 
http.get(`/api`)
    .then(resp => {
        let data: IResponse = resp; // data: any
 
    });
複製程式碼

如果是上面兩種情況,則需要提前定義好型別,並新增型別註解。否則,我們對於是否新增型別註解,鼓勵,但不強求。因為大多數情況,我們在初始化賦值時TS就能很好的幫助我們自動確認好型別,並且通過 typeof 也可以獲取該值的型別。一舉兩得!

3、巧用 type 定義型別


// good one
let user = {
    name: `Lucy`,
    age: 20
}
type User = typeof user;
 
 
// deprecate
type User = {
    name: string;
    age: number;
};
let user: User = {
    name: `Lucy`,
    age: 20`
}
複製程式碼

如上第一種寫法,我們在宣告user變數時,即得到了值,又獲得了型別!反之,第二種寫法就有點囉嗦了。

4、使用TS改寫當前程式碼遇到各種錯誤問題?

  • 物件屬性不存在錯誤::
    這種情況一般在於,該物件值TS知道其有明確型別(不是any,如果是any就不會報錯了),但是當前要訪問的屬性不存在與其已知型別結構。這種情況分兩種辦法解決:

    • 如果能修改該值的型別宣告,那麼新增上缺損值的屬性即可
    • 否則,使用 // @ts-ignore 註釋,或者使用型別斷言,強制為 any 型別:(this.props as any).notExists
  • 型別不明確的錯誤:
    即一個值的型別可能被註解為聯合型別,那麼在直接訪問時,TS無法確定當前值到底屬於哪個精確的型別,所以會報告錯誤。這種情況有以下解決拌飯:

    • 使用型別保護(type guards)
    • 使用型別斷言
    • 使用 // @ts-ignore 註釋

應該優先考慮型別保護,因為型別保護本質上就是增加程式碼邏輯,幫助TS理解確定當前型別,所以程式碼也會更健壯。而後兩種辦法,除非明確知道此時該值就是確定的型別,否則即使通過了TS編譯器,在程式碼執行階段,依然有可能出錯!

  • 值可能不存在的或為undefined的錯誤:

    • 這種情況其實是上面提到的型別不明確錯誤的一種,一般發生在可選屬性或者可選引數時。解決這些情況,最簡單的就是使用非空型別斷言(前提是確認該值確實是非空):

    • 非空型別斷言的形式是在值後面新增半形感嘆號:

someVar!.toString();
複製程式碼

相關文章