我有以下类型声明:
type Root = { r: string };
type A = { a: string };
type B = { b: string };
type Main = Root & (A | B);
由于Main
与{r: string, a: string} | {r: string, b: string}
等效,因此可以:
const main: Main = {
r: 'r',
a: 'a'
}
这里不足为奇。但是,这将引发以下错误:
const func : (main: Main) => void = main => {
main.a
/* ^
* [TS2339]
* Property 'a' doesn't exist on type 'Main'.
* Property 'a' doesn't exist on type 'Root & B' */
}
我确实知道.a
上不存在Root & B
,但是它存在于Root & A
上,因此它必须存在于(Root & A) | (Root & B)
上,它等效于{{1 }},对吧?
是一个错误,还是我错过了什么?
答案 0 :(得分:3)
您对Main
等同于(Root & A) | (Root & B)
是正确的,而对联合类型(|
)的解释是错误的。联合类型意味着您可以将联合中的任何一种类型分配给main
(因此(Root & A)
或(Root & B)
),但是您只能访问联合成员的公共属性。在这种情况下,公共成员仅为r
。由于main
可能是(Root & A)
或(Root & B)
,a
可能不存在于main
上,因此打字稿会阻止这种访问。
要使用仅在联合中的一种类型上存在的成员,您需要类型保护。在这种情况下,in
类型防护将最有效:
const func : (main: Main) => void = main => {
if ('a' in main) {
main.a
} else {
main.b
}
}
您可以阅读有关类型防护here
的更多信息答案 1 :(得分:2)
存在一个问题,编译器此时无法确保.a
或.b
可用,因为这将在运行时进行验证。一旦创建了Main
类型的变量,就将指定Main的特殊类型。因此,Root & A
或Root & B
。
要确保在该函数中可以访问.a
或.b
,只需执行以下操作:
type Root = { r: string };
type AB = { a?: string, b?: string };
type Main = Root & AB;
const func = (main: Main): void => {
if ('a' in main) {
main.a!
} else {
main.b!
}
}