🚀【TypeScript入門手冊】記錄了出場率較高的Ts概念,旨在幫助大家了解并熟悉Ts
🎉 本系列會持續更新并更正,重點關照大家感興趣的點,歡迎同學留言交流,在進階之路上,共勉!
star本專案給作者一點鼓勵吧
一、認識Narrowing
試想我們有這樣一個函式,函式名為 padLeft:
該函式實作的功能是:如果引數 padding 是一個數字,我們就在 input 前面添加同等數量的空格,而如果 padding 是一個字串,我們就直接添加到 input 前面,
讓我們實作一下這個邏輯:
function padLeft(padding: number | string, input: string) {
return new Array(padding + 1).join(" ") + input;
// 運算子“+”不能應用于型別“string | number”和“number”
}
如果這樣寫的話,編輯器里 padding + 1 這個地方就會標紅,顯示一個錯誤,?這是 TypeScript 在警告我們,如果把一個 number 型別 (即例子里的數字 1 )和一個 number | string 型別相加,也許并不會達到我們想要的結果,換句話說,我們應該先檢查下 padding 是否是一個 number:
function padLeft(padding: number | string, input: string) {
if (typeof padding === "number") {
return new Array(padding + 1).join(" ") + input;
}
return padding + input;
}
console.log(padLeft(10, "哈哈"));
這個代碼看上去也許沒有什么有意思的地方,但實際上,TypeScript 在背后做了很多東西,
TypeScript 要學著分析這些使用了靜態型別的值在運行時的具體型別,目前 TypeScript 已經實作了比如 if/else 、三元運算子、回圈、真值檢查等情況下的型別分析,
在我們的 if 陳述句中,TypeScript 會認為 typeof padding === number 是一種特殊形式的代碼,我們稱之為型別保護(type guard),TypeScript 會沿著執行時可能的路徑,分析值在給定的位置上最具體的型別,
TypeScript 的型別檢查器會考慮到這些型別保護和賦值陳述句,而這個將型別推導為更精確型別的程序,我們稱之為收窄 (narrowing), 在編輯器中,我們可以觀察到型別的改變:
function padLeft(padding: number | string, input: string) {
if (typeof padding === "number") {
return new Array(padding + 1).join(" ") + input;
// (parameter) padding: number
}
return padding + input;
// (parameter) padding: string
}
從上圖中可以看到在 if 陳述句中,和剩余的 return 陳述句中,padding 的型別都推導為更精確的型別,
接下來,我們就介紹 narrowing 所涉及的各種內容,
二、typeof收窄(type guards)
JavaScript 本身就提供了 typeof 運算子,可以回傳運行時一個值的基本型別資訊,會回傳如下這些特定的字串:
- “string”
- “number”
- “bigInt”
- “boolean”
- “symbol”
- “undefined”
- “object”
- “function”
typeof運算子在很多 JavaScript 庫中都有著廣泛的應用,而 TypeScript 已經可以做到理解并在不同的分支中將型別收窄,?在 TypeScript 中,檢查typeof回傳的值就是一種型別保護,
function getText(str: number | string): string {
if (typeof str === "number") {
return `${str} isNumber`;
// (parameter) str: number
} else {
return `${str} isString`;
// (parameter) str: string
}
}
三、等值收窄(Equality narrowing)
Typescript 也會使用 switch 陳述句和等值檢查比如 == !== == != 去收窄型別,比如:
function getText(a: string | boolean, b: string | null): void {
if (a === b) {
console.log(a);
console.log(b);
// (parameter) a: string
// (parameter) b: string
} else {
console.log(a);
console.log(b);
// (parameter) a: string | boolean
// (parameter) b: string
}
}
在這個例子中,我們判斷了x和y是否完全相等,如果完全相等,那他們的型別肯定也完全相等,而string型別就是x和y唯一可能的相同型別,所以在第一個分支里,x和y就一定是 string 型別,?判斷具體的字面量值也能讓 TypeScript 正確的判斷型別,
四、in 運算子收窄
JavaScript 中有一個 in 運算子可以判斷一個物件是否有對應的屬性名,TypeScript 也可以通過這個收窄型別,?舉個例子,在 “value” in x 中,“value” 是一個字串字面量,而 x 是一個聯合型別:
type Dog = { ww: "1"; mm?: "2" };
type Cat = { mm: "1" };
function inDemo(animal: Dog | Cat): void {
if ("ww" in animal) {
console.log(animal);
// (parameter) animal: Dog
} else {
console.log(animal);
// (parameter) animal: Cat
}
}
通過 “ww” in animal ,我們可以準確的進行型別收窄,
而如果有可選屬性,Ts也會檢測出來:
type Dog = { ww: "1"; mm?: "2" };
type Cat = { mm: "1" };
function inDemo(animal: Dog | Cat): void {
if ("mm" in animal) {
console.log(animal);
// (parameter) animal: Dog | Cat
} else {
console.log(animal);
// (parameter) animal: Cat
}
}
五、instanceof 收窄
instanceof 也是一種型別保護,TypeScript 也可以通過識別 instanceof 正確的型別收窄:
function instanceofDemo(a: object | number): void {
if (a instanceof String) {
console.log(a);
// (parameter) a: String
} else {
console.log(a);
// (parameter) a: number | object
}
}
六、賦值陳述句(Assignments)
TypeScript 可以根據賦值陳述句的右值,正確的收窄左值,
let x = Math.random() > 0.5 ? "abc" : 123;
x = 1;
// let x: string | number
console.log(x);
// let x: number
x = "1";
// let x: string | number
console.log(x);
// let x: string
注意這些賦值陳述句都有有效的,即便我們已經將 x 改為 number 型別,但我們依然可以將其更改為 string 型別,這是因為 x 最初的宣告為 string | number,賦值的時候只會根據正式的宣告進行核對,?
寫在最后
本篇文章是《Typescript基礎入門》第二篇,收窄是一組比較難理解的思路,這里僅提到部分常見的形式,一起共勉吧!
參考:
- TypeScript4 中文檔案
關于我:
- 花名:余光
- 郵箱:webbj97@163.com
- csdn:傳送門
其他沉淀:
- Github: Js版LeetCode題解
- 余光的前端成長筆記
- 高頻手撕代碼系列
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/396230.html
標籤:其他
