TS2339-明显有效的TS文件中的“类型上不存在属性”错误

时间:2018-12-12 13:15:28

标签: typescript

我有以下类型声明:

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 }},对吧?

是一个错误,还是我错过了什么?

2 个答案:

答案 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 & ARoot & 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!
    }
}