繁体   English   中英

如何使 Discriminated Unions 与解构一起工作?

[英]How to make Discriminated Unions work with destructuring?

考虑以下三种类型,其中MainTypeType1Type2并集。 如果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 的新手,所以我无法了解解构如何改变类型。 请解释原因,并告诉有什么方法可以解决它。

通过在函数参数级别使用解构,我们松散了kinddata之间的联系。 因此,按kind切换不会像现在那样缩小data因为它们处于不同的数据结构中。

我可以说你删除了kinddata之间的界限,这意味着你真的引入了两个变量,一个类型为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 }
  }
}

通过使用类型保护isKind1isKind2我们能够在这两个变量之间创建连接。 但问题是我们不能再使用switch ,我们还有更多的代码,以及在函数中实现的字段关系而不是类型定义,这种方法容易出错,因为我可以在函数中做不同的关系,然后原始类型正在定义。

明确地说,我正在展示它是可能的,但它不值得,我建议保留原始实现而不破坏。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM