跳至主要内容

[Day21] TS:Conditional Chain

雖然昨天說 TypeScript 已經差不多,但其實還有一個(或一些?)還沒寫到。我們來看一段程式碼:

conditional chain

上面這個是在 React 中的一段型別定義,今天沒有要細部看裡面的每個部分,而是著重在 Day08 時提到的 Conditional Type 的部分,通常當有多個條件判斷 if...else if ... else if ... else 的時候,為了避免難以閱讀,我們不會用三元運算子這樣的寫法,可能會改用 switch 等其他寫法,然而在 TypeScript 中,要表達條件式沒有其他的方法,還是只能透過三元運算子,所以你有時會看到上面這種排列,這種串連 ? : 的寫法稱作 Conditional Chains。

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; }
}

對應著剛剛看到的那段原始碼,就可以發現:

Conditional Chains

它其實是由三個條件判斷是所組成。也就是:

if C extends { propTypes, defaultProps } ... Defaultize ...
else if C extends { propTypes } ... MergePropTypes ...
else if C extends { defaultProps } ... Defaultize
else P

這裡在做的事情,其實就是判斷這個泛型 C 是同時帶有 propTypesdefaultProps,或只有帶有其中之一的情況,分別要回傳不同的型別。這裡你也可以看到筆者曾在 Day10 提到的,在使用 Conditional Types 時,還可以使用 infer 來取出對應的型別使用。

雖然我們單從這裡可能還沒有辦法完全理解這段 Utility Types 做了什麼,但至少我們大概可以了解在不同的條件下,它會在呼叫不同的 Utility Types 來回傳不同的型別。

Nested Conditional Chains

如果是像上面那種單純的 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 中因為沒有 ifswitch 這種關鍵字,所以最好的方式就是透過良好的縮排來幫助閱讀。

但真的還是很不好閱讀就是...

Conditional Chains

參考資料