iT邦幫忙

2022 iThome 鐵人賽

DAY 10
1

哇,居然已經到第十天了,不知不覺也完成了1/3,有些感動,希望之後能穩定發揮!
目前我們都只聊到很粗淺的TypeScript概念,但沒有這些概念,也沒辦法繼續往下走,今天就讓我們複習一下到目前為止的內容吧。

要解決的問題

TypeScript的出現,就是為了要解決JavaScript作為「弱型別的語言」而生的,弱型別大概可以理解為,我們在宣告一個變數時,不用事先為他定義一個型別,在宣告後,也可以將變數從ex:字串->轉為數字。這點不全然是壞事,但對於要從強型別語言跨來JavaScript的開發者來講,就會非常不習慣,且程式也有可能因為這個特性,發生非預期的錯誤,因此才需要有TypeScript來幫我們減少可能發生的錯誤。對,他的確有學習及使用成本,但整理來說是值得的。

簡單的型別介紹

TypeScript有很多種型別可以讓我們使用,最能直接想到的就是stringnumberboolean。我們可以在程式碼當中先將特定變數設定成這些型別,舉例來說,若我們的函式中有個參數是age: number,我們在函式內部若想對age使用字串才有的方法ex: age.toUpperCase(),程式碼便會在編譯前就直接秀出錯誤,避免我們到很後期才發現這個錯誤行為。不僅如此,在你打字的過程中,一打完age.的那個.,編輯器就會直接秀出只有數字型別才會有的方法推薦了。如果你的參數是個物件,在函式內也一樣會產生相對應的屬性名稱提示。

聯集

我們也學到了型別聯集Type Union,讓我們可以不侷限於一個特定型別。若我們將函式參數設定為age: number | string,在呼叫時便能帶入數字或字串都不會報錯,但必須注意的是,函式內部若想直接操作age而沒有先進行型別防衛Type Guard的話,就必須使用"數字跟字串"都有的方法。要型別防衛,最簡單的方法就是多寫一個判斷式:if (typeof age === "number"){就做number的事},便能化解這個狀況。

型別斷言

如果覺得型別防衛很麻煩,那我們可以進行型別斷言Type Assertion,舉例來說,我們的函式如果會視情況回傳數字或字串,我們可以在回傳時"斷言"他會是什麼型別,let result = foo() as number,這樣就能讓編輯器知道”你知道自己在做什麼“,但斷言不代表他會強制幫你將函式內的執行結果"轉型",你只能斷言他原本就會回傳的特定型別,像這例子我們就只能斷言他是number或是string,但如果你真的想要將他斷言成其他型別,就先將它斷言成any/unknown,再斷言成你想要的型別就可以了。所以斷言要謹慎,就算編輯器懂了,不代表其他人類看得懂&能理解。

更多型別

剛剛有提到unknownany,這兩個也是TypeScript的型別,不一樣的是,TypeScript比較不會去管你的any,你要對是any的變數做任何事都可以,但如果是unknown,因為是未知,所以TypeScript會叫你先確認了他的型別,再進行後續操作才會比較安全。還有兩個比較少使用到的nevervoidnever是代表不可能被回傳/執行的值、void則代表沒有回傳任何值(像是單純的console.log)。

型別別名 與 介面

如果一直要在參數中寫上number | string,有點麻煩。我們可以使用型別別名Type Alise來將特定組合的型別先定義起來,寫起來會像這樣type Person = number | string,未來在使用它時,便能變成age : Person,會跟age: number | string一樣意思,不過字面上又多了更多資訊,更好判讀了。

除了型別別名能這樣做,TypeScript還有一個很像的概念,叫做介面Interface,他會長這樣:

type Person = {
    name: string
    age: number
}

interface Person {
    name: string
    age: number
}

如果出現了同名的interface,只要他裡面的屬性名稱沒有衝突,便會直接跟先前的interface重合,我們也能透過關鍵字extends擴充。使用型別別名時要擴充也是可以的,不過是用"&"關鍵字,而非extends。type跟interface是可以混用的,

interface Name {
    name: string
};

interface Age {
    age: number
};

type Person = Name & Age;

let guy: Person = {
    name: "John",
    age: 18
}

但如果可以的話,建議從頭到尾使用同一種寫法,比較一致跟好理解,網路上比較推薦的都是使用interface居多。

我們有時候可能不確定interface/type當中會有哪些屬性,所以可以透過問號"?"來將某些屬性設為選擇性的,從下面例子來看,若將函式的參數設為FriedRice這個型別,就不一定要提供ingredients,但函式內要寫好"若ingredients不存在"的判斷式。如果有些屬性你希望我們後續只能讀取他,而不允許修改它,則可以加上readonly這個關鍵字,但如果使用了readonly關鍵字的那個屬性是個物件,其內部還是可以被修改的,就跟使用const來宣告物件一樣道理。

interface FriedRice {
    readonly name: string
    price: number
    ingredients?: string[]
}

小結:
花了一天的頁面來複習前面所提到的內容,如果發現對任何地方不熟悉,就要趕快往前翻,或者趕快去看官方文件了!
明天要講什麼還沒想到 0rz,只能先預祝大家週一順利了!!


上一篇
第九天! 選擇性屬性與唯讀屬性
下一篇
第11天!淺談Tuple 元組 與 Enum 列舉
系列文
你也對開始使用typescript感到無力嗎?我也是 - 30天初探typescript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言