雖然昨天說 TypeScript 已經差不多,但其實還有一個(或一些?)還沒寫到。我們來看一段程式碼:
上面這個是在 React 中的一段型別定義,今天沒有要細部看裡面的每個部分,而是著重在 Day08 時提到的 Conditional Type 的部分,通常當有多個條件判斷 if...else if ... else if ... else
的時候,為了避免難以閱讀,我們不會用三元運算子這樣的寫法,可能會改用 switch
等其他寫法,然而在 TypeScript 中,要表達條件式沒有其他的方法,還是只能透過三元運算子,所以你有時會看到上面這種排列,這種串連 ?
:
的寫法稱作 Conditional Chains。
實際上 Conditional Chains 並不是 TypeScript 特有的東西,只是一般有其他選擇的情況下(例如,JavaScript)我們不會這樣寫。雖然第一眼看到時頭很痛,但其實如果 Conditional Chain 有適當排列的話,並沒有想像的這麼難懂。
在 MDN 中提供了 Conditional Chains 很好的範例:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator#conditional_chains
function example(…) {
return condition1 ? value1
: condition2 ? value2
: condition3 ? value3
: value4;
}
// Equivalent to:
function example(…) {
if (condition1) { return value1; }
else if (condition2) { return value2; }
else if (condition3) { return value3; }
else { return value4; }
}
對應著剛剛看到的那段原始碼,就可以發現:
它其實是由三個條件判斷是所組成。也就是:
if C extends { propTypes, defaultProps } ... Defaultize ...
else if C extends { propTypes } ... MergePropTypes ...
else if C extends { defaultProps } ... Defaultize
else P
這裡在做的事情,其實就是判斷這個泛型 C
是同時帶有 propTypes
和 defaultProps
,或只有帶有其中之一的情況,分別要回傳不同的型別。這裡你也可以看到筆者曾在 Day10 提到的,在使用 Conditional Types 時,還可以使用 infer
來取出對應的型別使用。
雖然我們單從這裡可能還沒有辦法完全理解這段 Utility Types 做了什麼,但至少我們大概可以了解在不同的條件下,它會在呼叫不同的 Utility Types 來回傳不同的型別。
如果是像上面那種單純的 Conditional Chains 還算好理解,但有些時候還會有 nested 的 conditional chains,這時候縮排就又顯得更重要了,例如:
function example(…) {
if (condition1) {
if (condition1_1) {
return value1;
} else {
return value1_1;
}
} else if (condition2) {
return value2;
} else {
return value4;
}
}
寫成三元運算子就會像這樣:
function example() {
return condition1
? condition1_1
? 'value1'
: 'value1_1'
: condition2
? 'value2'
: 'value4';
}
我知道有點嚇人,第一眼看到有點嚇人,但在 TypeScript 中因為沒有 if
或 switch
這種關鍵字,所以最好的方式就是透過良好的縮排來幫助閱讀。
但真的還是很不好閱讀就是...