gpt4 book ai didi

javascript - 联合类型缺少属性

转载 作者:搜寻专家 更新时间:2023-11-01 04:28:48 25 4
gpt4 key购买 nike

假设我有以下类型:

type MessageType = 'example1' | 'example2' | 'example3'

type MessageHead = {
+type: MessageType
}

type BaseBody = {
+payload?: any,
+data?: any
}

type LabelledBody = {
+labelName: string
}

type MessageBody = BaseBody | LabelledBody

type Message = MessageHead & MessageBody

然后我像这样消费一条消息:

[{name: 'example1'}, {name: 'potato'}].find(thing => thing.name === message.labelName)

导致以下流程异常:

Cannot get message.labelName because:
• all branches are incompatible:
• Either property labelName is missing in MessageHead [1].
• Or property labelName is missing in BaseBody [2].
• ... 1 more error.

type Message = MessageHead & MessageBody 被显示为违规类型

我不明白的是为什么我的联合类型不允许带有标签名的消息?

编辑:Tryflow 链接:Tryflow link

最佳答案

您的联合类型确实允许带有标签名的消息。问题是它还允许 Message 没有标签名称。考虑一下您在这条线上的工会:

type MessageBody = BaseBody | LabelledBody

这意味着 MessageBody 可以是这样的:

type BaseBody = {
+payload?: any,
+data?: any
}

type LabelledBody = {
+labelName: string
}

更进一步,我们可以执行 MessageBody 和 MessageHead 之间的交集,并看到 Message 的形状可以是以下两种情况之一:

(案例一)

{
+type: MessageType, // From MessageHead
+payload?: any, // From BaseBody
+data?: any // From BaseBody
}

(案例2)

{
+type: MessageType, // From MessageHead
+labelName: string // From LabelledBody
}

因此,当 Flow 看到您正在访问 message 对象的 labelName 时,它​​会(正确地)相信 message 对象可能看起来像案例 1(上文) .如果我们是情况 1,那么您无法访问 labelName,因为它不存在,因此会抛出错误。解决此问题的最简单方法是创建两种类型的消息,一种带有 labelName,另一种带有 payloaddata 属性。然后您可以将您的函数注释为接收其中一种类型:

( Try )

type MessageWithLabel = MessageHead & LabelledBody

const exFunc = (message: MessageWithLabel) => {
[{name: 'example1'}, {name: 'potato'}].find(thing => thing.name === message.labelName)
}

或者,您可以使用 disjoint union告诉流程您正在使用哪种情况。此策略涉及设置一个属性(例如 type),它告诉流我们正在处理哪种类型的对象。

( Try )

type MessageWithBody = {|
+type: 'base',
+payload?: any,
+data?: any
|}

type MessageWithLabel = {|
+type: 'labelled',
+labelName: string
|}

type Message = MessageWithBody | MessageWithLabel

const exFunc = (message: Message) => {
if (message.type === 'labelled') {
const labelName = message.labelName
return [{name: 'example1'}, {name: 'potato'}].find(thing => thing.name === labelName)

// Sidenote:
// I had to extract labelName to a constant for Flow to typecheck this correctly.
// So if we used thing.name === message.labelName Flow will throw an Error.
// If you don't extract it right away, flow thinks the Message may have changed
// after pretty much any non-trivial action. Obviously it doesn't change in this
// example, but, hey, Flow isn't perfect.
// Reference: https://flow.org/en/docs/lang/refinements/#toc-refinement-invalidations
} else {
// Do something for the 'base' type of message
}
}

关于javascript - 联合类型缺少属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49351349/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com