如何使受歧视的工会进行解构工作? [英] How to make Discriminated Unions work with destructuring?

查看:49
本文介绍了如何使受歧视的工会进行解构工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下三种类型,其中 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆