我有这种情况,没有办法有意义地改变数据结构。所以我无法添加标签。 有没有办法区分没有标签的类型?我试过鸭子,但它不起作用。查看我的example
type Result = Done | Error; // a disjoint union type with two cases
type Done = { count: number }
type Error = { message: string }
const doSomethingWithDone = (obj: Done) => {/*...*/}
const doSomethingWithError = (obj: Error) => {/*...*/}
const f = (result: Result) => {
if (result.count) {
doSomethingWithDone(result)
} else {
doSomethingWithError(result)
}
}
错误是:
5: const doSomethingWithDone = (obj: Done) => {/*...*/}
^ property `count`. Property not found in
10: doSomethingWithDone(result)
^ object type
6: const doSomethingWithError = (obj: Error) => {/*...*/}
^ property `message`. Property not found in
12: doSomethingWithError(result)
^ object type
答案 0 :(得分:1)
Flow不支持这种优雅的东西,因为它不相交联盟。但是,确切类型可以提供帮助。你的例子中的问题是我能做到
const x: Error = {message: 'foo', count: 'bar'};
f(x);
赋值有效,因为我的对象文字满足x
接口。所以,虽然你知道如果某个东西是Error
,它有一个message
属性,你不知道它有什么其他属性。因此,检查count
属性是否存在并不能证明您拥有Done
类型的有效对象。
确切类型可以在这里提供帮助:
type Result = Done | Error; // a disjoint union type with two cases
type Done = {| count: number |}
type Error = {| message: string |}
const doSomethingWithDone = (obj: Done) => {/*...*/}
const doSomethingWithError = (obj: Error) => {/*...*/}
const f = (result: Result) => {
if (result.count) {
doSomethingWithDone(result)
} else if (result.message) {
doSomethingWithError(result)
}
}
// Expected error. Since Error is an exact type, the count property is not allowed
const x: Error = {message: 'foo', count: 'bar'};
f(x);
请注意,除了使类型完全正确外,我还必须将else
更改为else if
。显然,使用精确类型的缺点是你的对象不能有无关的字段。但是,如果你绝对不能添加一个鉴别器字段来使用不相交的联合,我认为这是最好的选择。
答案 1 :(得分:0)
这是有道理的,因为你的打字并没有说
Done
不能有计数属性。正如您在example中所看到的那样,使用精确对象类型似乎在某种程度上可以正常工作。可悲的是,你还必须在别的地方做一个明确的检查。