iT邦幫忙

2022 iThome 鐵人賽

DAY 15
0

再談設定檔

昨天講了設定檔的大概,並用tsc初始化的設定檔給大家看了一下,到底有哪些選項能用。那今天就讓我們來簡單看看幾個選項開啟後,會是什麼效果,讓大家對設定檔更有概念。

以下範例沒有先後順序之分,就只是單純列出來讓大家看看效果而已,已經熟悉設定檔,或覺得現在看了也記不住的話,可以直接跳過沒關係!

這邊先假設大家用的是最原始、設定最少的設定檔。

suppressExcessPropertyErrors

雖然字面上的意思已經超級明確了,但還是讓我們來看看下面例子:

interface Person{
    name:string
    age:number
}

const john:Person = {
    name:"John",
    age:18,
    property:["house"]
}

我們這邊有個Person介面,內含應該要是字串的name及應該要是數字的age,接著宣告一個常數john,將其型別註解設為Person,所以他應該只能有nameage而已,但我們多放了個property進去。我們都知道,JavaScript並不會阻止我們將新的屬性/方法加進去物件當中,只是TypeScript會在這邊報錯,覺得你多放了些什麼。

property明顯出錯了

文字會寫著 Type '{ name: string; age: number; property: string[]; }' is not assignable to type 'Person'. Object literal may only specify known properties, and 'property' does not exist in type ‘Person'.

要解決這個error,我們可以透過打開suppressExcessPropertyErrors這個flag來解決。顧名思義,他就是要抑制多出來的屬性所產生的錯誤。我們這邊畢竟是合法的JavaScript,一個物件要加多少屬性或方法都是可以的,所以,只要你知道你在幹什麼,就能將這個flag打開,TypeScript便不會噴錯了。

noEmitOnError

這也很淺顯易懂lol,只要將這個flag打開,只要你的ts檔案在編譯過程中有任何error,就不會幫你編譯成js檔案,但如果沒有開啟這個flag,在編譯過程僅管會報錯,但tsc仍然會幫你把檔案轉成js檔。

console會顯示錯誤,並不讓你編譯,修好再來吧!

noImplicitReturns

寫過JavaScript的人都知道,要是在函式內部沒有特地寫明要回傳什麼值,他就會傳回undefined,這種特性被叫做"隱性傳回"(implicit return),因此,若我們將這個flag給打開,tsc就會幫我們檢查是否有函式裡面沒有明確的return。

function calculatePrice(amount: number | null) {
  if (amount != null) {
    return amount * 1.02
  }
}

上面這個例子,我們只有檢查amount在不是null的時候,才有回傳值。所以,tsc會告訴我們:Not all code paths return a value.。但這邊有趣的是,這個flag開了後,只是會有黃色警告性質的錯誤訊息,tsc仍然會幫我們將檔案編譯好後輸出。

strictNullChecks

這個flag很好玩!會改變TypeScript推論型別的結果。至於要怎麼知道TypeScript推論型別後的結果..我們可以在設定檔內compilerOptions加上這一行:

{
    "declaration": true
}

意思就是我們要將tsc檔內有宣告的變數的型別列出來,加上這行後,每次編譯時就會產生一個.d.ts的檔案,我們叫做"型別宣告檔"。我們用上面的calculatePrice例子來實驗看看,會產生什麼內容:

declare function calculatePrice(amount: number | null): number;

我們得到了一個開頭為declare、中間提示了我們參數的型別的句子,有趣的是,他這邊直接幫我們寫出"TypeScript"所預期的回傳型別了!所以,這個檔案好處在於(但不限於)能夠明確寫出TypeScript編譯後的預期行為,大部分時間來講,TypeScript的預期行為都是最精確的,但如果跟你所預期的有落差,就得趕快來看看差別在哪裡、是什麼造成這個落差的。

宣告型別檔是個很重要的觀念,一時半刻難以說清,很多第三方套件,若沒有這個檔案,編輯器是不會提示我們所引入的函式是要怎麼使用的。這邊只能先簡單帶過。

回到strictNullChecks,剛剛說他會改變TypeScript推論型別的結果。讓我們來看個超簡單的例子,如果我們在.ts檔內寫下以下內容:

let array = []

聰明的你已經能猜出,在還沒加上strictNullChecks這個flag前,TypeScript會將他判斷為any[],這點我們可以從剛剛提到的型別宣告檔看到他編譯後的型別:

declare let array: any[];

所以,我們在後面的程式碼中,基本上要對arraypush任何值都是可以的,因為他接受any型別嘛。但any幾乎就代表TypeScript不會對他進行任何檢查,所以開啟strictNullChecks後,編譯器就會嚴格限制nullundefined值的使用,並禁止編譯器將空陣列推論為any型別。所以,編譯器只能將array陣列推論為never型別了!

(將strictNullChecks打開後,執行tsc指令,再進到型別宣告檔內查看)

declare let array: never[];
//哇,真的變never了

我們後續將無法把任何東西塞進這個陣列內。所以這個flag強制我們一定要進行型別宣告,避免後續非預期性的錯誤產生。

//在ts檔內改成這樣:
let array = [] as number[]

//在.d.ts檔內就會變成:
declare let array: number[];

小結:設定檔還能講的東西太多太多了,今天簡單介紹這幾個可能比較常見的flag,請讀者有興趣+有空的話,一定要將各個flag都打開來,甚至去看看產生後的型別宣告檔,或許你會發現非預期的結果喔。

週末愉快!


上一篇
第14天!來看看TypeScript的設定檔(tsconfig.json)
下一篇
第16天!泛型Generic Types
系列文
你也對開始使用typescript感到無力嗎?我也是 - 30天初探typescript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言