如何使受歧视的工会进行解构工作? [英] How to make Discriminated Unions work with destructuring?
问题描述
请考虑以下三种类型,其中 MainType
是 Type1
和 Type2
的并集.如果 kind
是"kind1"
,则 data
的类型应为 {msg:string}
,与相同Type2
Consider the following three types in which MainType
is union of Type1
and Type2
. If kind
is "kind1"
then data
should be of type {msg: string}
same from Type2
interface Type1 {
kind: "kind1";
data: { msg: string };
}
interface Type2 {
kind: "kind2";
data: { msg2: string };
}
type MainType = Type1 | Type2;
这是使用它的第一种方法.
Here is the first way to use it.
function func(obj: MainType) {
switch (obj.kind) {
case "kind1": return obj.data.msg;
case "kind2": return obj.data.msg2;
}
}
上面的代码没有错误,并显示正确的自动完成功能.
The above code gives no error and shows correct autocomplete.
但是当我们破坏 obj
的结构时,它会给出错误信息.
But when we destructure the obj
then it gives error.
function func({kind, data}: MainType) {
switch (kind) {
case "kind1": return data.msg;
case "kind2": return data.msg2;
}
}
错误是
属性
'msg'
在类型'{msg:string;} |{msg2:字符串;}'
也许这是非常基本的东西.但是我对ts还是陌生的,所以我不了解解构如何改变类型.请说明原因,并告诉您有什么方法可以解决它.
Maybe its something very basic. But I am new to ts so I can't get how destructuring changes the types. Please explain the reason and also tell is there any way to fix it.
推荐答案
通过在函数参数级别进行分解,我们可以松开种类
和 data
之间的连接.因此,按<种类>切换种类>不会缩小数据
的范围,因为它们现在处于不同的数据结构中.
By using destructuring at level of function argument we loose connection between kind
and data
. So switch by kind
is not narrowing the data
as now they are in different data structures.
我可以说您消除了 kind
和 data
之间的界限,这意味着您实际上引入了两个变量,一个类型为 kind1 |.kind2
和第二个类型为 {msg:string;} |{msg2:字符串;}
.
I can say you remove the bound between kind
and data
what means that you really introduce two variables, one with type kind1 | kind2
and second with type { msg: string; } | { msg2: string; }
.
结果,我们不再具有 kind
形式的判别式.
In result we don't have discriminant in form of kind
anymore.
以下等同于破坏行为的代码:
Below equivalent code to destructuring behavior:
const f = (t: MainType) => {
const kind = t.kind // "kind1" | "kind2";
const data = t.data // {msg: string;} | {msg2: string;}
}
是的,从逻辑角度来看,您的代码是完全可以的,因为我们知道这些字段之间的关系,所以它应该可以工作.不幸的是,TS无法理解界限.
And yes from the logic perspective your code is fully ok, it should work as we know the relation between these fields. Unfortunately TS is not able to understand the bound.
总结-不幸的是,除非您不将类型缩小为工会的特定成员,否则您将无法使用解构,因为这会破坏字段之间的类型关系.
In summary - unfortunate until your don't narrow the type to specific member of the union, you cannot use destructuring, as it will ruin the type relationship between fields.
我们可以考虑一些类型保护者的解决方法.考虑以下示例:
We can think about workaround by some type guards. Consider following example:
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
了,我们还有更多的代码,并且字段关系在函数中实现,而不是在类型定义中实现,这种方法容易出错,因为我可以在函数中做与原始方法不同的关系类型在定义.
By using type guards isKind1
and isKind2
we are able to create a connection between these two variables. But the issue is we cannot use switch
anymore, we also have more code, and field relation implemented in functions and not type definitions, such approach is error prone as I can do different relation in function then the original type is defining.
为清楚起见,我正在展示这是可能的,但值得一试,我建议保留原始实现而不破坏结构.
To be clear I am showing it is possible but its not worth the candle and I suggest to keep the original implementation without destructuring.
这篇关于如何使受歧视的工会进行解构工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!