[ Day-003 ] TypeScript 型別限縮 Narrowing
使用 type guards 做型別限縮 Narrowing
Type Guards
Type Guards 可以讓 TypeScript 在當程式碼出現分支
branch
註解1 時
可以進行型別的限縮Narrowing
原先 Type Guards 用在 JavaScript 時可以使用 typeof 去判定任一變數型別 但卻只能生效在 runtime
而如果在 TypeScript 使用 typeof 去判定型別時
就有能力提供更多資訊給 TypeScript 在 compile 時期就能知道型別差異Type Guardstypeof 'apple' === 'string';
typeof 100 === 'number';
typeof 9007199254740991n === 'bigint';
typeof true === 'boolean';
typeof Symbol('foo') === 'symbol';
typeof undefined === 'undefined';
typeof null === 'object'; // 特別容易混淆部分
typeof {} === 'object';
typeof [] === 'object'; // 特別容易混淆部分不是 array 是 object
typeof new Map() === 'object'; // 特別容易混淆部分
typeof new Set() === 'object'; // 特別容易混淆部分
function hello() {}
typeof hello === 'function';
const world = () => {};
typeof world === 'function';Narrowing Case
了解 Type Guards 有哪些選項可以使用後
可以實際來看一個在 TypeScript 上使用的案例原先有一函式 padLeft 可以傳入名為
padding
而型別是number 或 string
如果在下面實作當中
TypeScript 將會 compile error
原因是 String.repeat 註解2 本身只接收型別為number
的 count 參數
但在此案例下 padding 卻有可能不是 number 而是 stringfunction padLeft(padding: number | string, input: string): string {
return ' '.repeat(padding) + input;
}所以在上面案例當中 我們需要使用 Type Guards
去幫我們在程式碼的建出分支
用來限縮一部分的型別的情境function padLeft(padding: number | string, input: string) {
if (typeof padding === 'number') {
// 在這一區塊 padding 只會是 number 所以可以安心使用 String.repeat
return ' '.repeat(padding) + input;
}
// 在這一區塊 padding 只會是 string
// 因為 padding 不是 number 就是 string
// 只有兩種可能性
return padding + input;
}
Truthiness Narrowing
上面案例看完後
可以發現typeof null
是object
那我們該如何 Narrowingnull
我們可以透過Truthiness Narrowing
在 JavaScript 當中包含以下falsy
值Boolean(null) === false;
Boolean(undefined) === false;
Boolean(false) === false;
Boolean(NaN) === false;
Boolean(0) === false;
Boolean(-0) === false;
Boolean(0n) === false;
Boolean('') === false;
Boolean(document.all) === false;於是再來看個案例
在這個案例當中可以看見
typeof strs === 'object'
時 strs 有機會是string[]
或是null
然而 null 沒有辦法被 iterate 因此要 iterate strs 時就產生 compile errorfunction printAll(strs: string | string[] | null) {
if (typeof strs === 'object') {
//'strs' is possibly 'null'.
for (const s of strs) {
console.log(s);
}
} else if (typeof strs === 'string') {
console.log(strs);
} else {
// do nothing
}
}這時可以透過
Truthiness Narrowing
解決這問題
當中加上了strs &&
字段
讓進入typeof strs === 'object'
分支當中的程式碼
不但要是object
且至少還要是truthy
function printAll(strs: string | string[] | null) {
if (strs && typeof strs === 'object') {
for (const s of strs) {
console.log(s);
}
} else if (typeof strs === 'string') {
console.log(strs);
}
}