昨天講了設定檔的大概,並用tsc
初始化的設定檔給大家看了一下,到底有哪些選項能用。那今天就讓我們來簡單看看幾個選項開啟後,會是什麼效果,讓大家對設定檔更有概念。
以下範例沒有先後順序之分,就只是單純列出來讓大家看看效果而已,已經熟悉設定檔,或覺得現在看了也記不住的話,可以直接跳過沒關係!
這邊先假設大家用的是最原始、設定最少的設定檔。
雖然字面上的意思已經超級明確了,但還是讓我們來看看下面例子:
interface Person{
name:string
age:number
}
const john:Person = {
name:"John",
age:18,
property:["house"]
}
我們這邊有個Person
介面,內含應該要是字串的name
及應該要是數字的age
,接著宣告一個常數john,將其型別註解設為Person
,所以他應該只能有name
跟age
而已,但我們多放了個property進去
。我們都知道,JavaScript並不會阻止我們將新的屬性/方法加進去物件當中,只是TypeScript會在這邊報錯,覺得你多放了些什麼。
文字會寫著 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便不會噴錯了。
這也很淺顯易懂lol,只要將這個flag打開,只要你的ts檔案在編譯過程中有任何error,就不會幫你編譯成js檔案,但如果沒有開啟這個flag,在編譯過程僅管會報錯,但tsc仍然會幫你把檔案轉成js檔。
寫過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仍然會幫我們將檔案編譯好後輸出。
這個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[];
所以,我們在後面的程式碼中,基本上要對array
push任何值都是可以的,因為他接受any型別嘛。但any幾乎就代表TypeScript不會對他進行任何檢查,所以開啟strictNullChecks後,編譯器就會嚴格限制null
與undefined
值的使用,並禁止編譯器將空陣列推論為any
型別。所以,編譯器只能將array
陣列推論為never
型別了!
(將strictNullChecks打開後,執行tsc指令,再進到型別宣告檔內查看)
declare let array: never[];
//哇,真的變never了
我們後續將無法把任何東西塞進這個陣列內。所以這個flag強制我們一定要進行型別宣告,避免後續非預期性的錯誤產生。
//在ts檔內改成這樣:
let array = [] as number[]
//在.d.ts檔內就會變成:
declare let array: number[];
小結:設定檔還能講的東西太多太多了,今天簡單介紹這幾個可能比較常見的flag,請讀者有興趣+有空的話,一定要將各個flag都打開來,甚至去看看產生後的型別宣告檔,或許你會發現非預期的結果喔。
週末愉快!