[英]How to make Discriminated Unions work with destructuring?
考慮以下三種類型,其中MainType
是Type1
和Type2
並集。 如果kind
是"kind1"
那么data
的類型應該是{msg: string}
與Type2
相同
interface Type1 {
kind: "kind1";
data: { msg: string };
}
interface Type2 {
kind: "kind2";
data: { msg2: string };
}
type MainType = Type1 | Type2;
這是使用它的第一種方法。
function func(obj: MainType) {
switch (obj.kind) {
case "kind1": return obj.data.msg;
case "kind2": return obj.data.msg2;
}
}
上面的代碼沒有給出錯誤並顯示正確的自動完成。
但是當我們解構obj
它會出錯。
function func({kind, data}: MainType) {
switch (kind) {
case "kind1": return data.msg;
case "kind2": return data.msg2;
}
}
錯誤是
屬性
'msg'
不存在於類型'{ msg: string; } | { msg2: string; }'
'{ msg: string; } | { msg2: string; }'
也許它的一些非常基本的東西。 但我是 ts 的新手,所以我無法了解解構如何改變類型。 請解釋原因,並告訴有什么方法可以解決它。
通過在函數參數級別使用解構,我們松散了kind
和data
之間的聯系。 因此,按kind
切換不會像現在那樣縮小data
因為它們處於不同的數據結構中。
我可以說你刪除了kind
和data
之間的界限,這意味着你真的引入了兩個變量,一個類型為kind1 | kind2
kind1 | kind2
和第二個類型為{ msg: string; } | { msg2: string; }
{ msg: string; } | { msg2: string; }
{ msg: string; } | { msg2: string; }
.
結果我們不再有kind
形式的判別kind
了。
下面是解構行為的等效代碼:
const f = (t: MainType) => {
const kind = t.kind // "kind1" | "kind2";
const data = t.data // {msg: string;} | {msg2: string;}
}
是的,從邏輯角度來看,您的代碼完全沒問題,因為我們知道這些字段之間的關系,所以它應該可以工作。 不幸的是,TS 無法理解界限。
總之- 不幸的是,除非您沒有將類型縮小到聯合的特定成員,否則您不能使用解構,因為它會破壞字段之間的類型關系。
我們可以考慮一些類型保護的解決方法。 考慮以下示例:
const isKind1 = (kind: MainType['kind'], data: MainType['data']): data is Type1['data']
=> kind === 'kind1'
const isKind2 = (kind: MainType['kind'], data: MainType['data']): data is Type2['data']
=> kind === 'kind2'
const f = ({kind, data}: MainType) => {
if (isKind1(kind, data)) {
data // is { msg: string }
}
if (isKind2(kind, data)) {
data // is { msg2: string }
}
}
通過使用類型保護isKind1
和isKind2
我們能夠在這兩個變量之間創建連接。 但問題是我們不能再使用switch
,我們還有更多的代碼,以及在函數中實現的字段關系而不是類型定義,這種方法容易出錯,因為我可以在函數中做不同的關系,然后原始類型正在定義。
明確地說,我正在展示它是可能的,但它不值得,我建議保留原始實現而不破壞。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.