联盟类型以意想不到的方式行事

时间:2017-08-29 14:03:42

标签: typescript

interface A {
  a: number;
}

interface B extends A {
  b: number;
}

let ab: A | B = {
  a: 1
};

ab.b = 2;

我认为这是一个有效的代码 - ab首先充当A,然后在添加字段后我希望它充当B。不幸的是它没有:

/usr/local/lib/node_modules/ts-node/src/index.ts:307
        throw new TSError(formatDiagnostics(diagnosticList, cwd, ts, lineOffset))
              ^
TSError: ⨯ Unable to compile TypeScript
test.ts (13,4): Property 'b' does not exist on type 'A'. (2339)
    at getOutput (/usr/local/lib/node_modules/ts-node/src/index.ts:307:15)
    at /usr/local/lib/node_modules/ts-node/src/index.ts:336:16
    at Object.compile (/usr/local/lib/node_modules/ts-node/src/index.ts:496:11)
    at Module.m._compile (/usr/local/lib/node_modules/ts-node/src/index.ts:392:43)
    at Module._extensions..js (module.js:580:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/usr/local/lib/node_modules/ts-node/src/index.ts:395:12)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Function.Module.runMain (module.js:605:10)

它似乎有错误的类型。它认为ab属于A类型,但它明确定义为类型A | B ...

我做错了吗?或者这是TypeScript不是那么好的类型系统的另一个实例?

编辑:为了澄清事情,我想要“或者”类型我认为是联合类型。我原以为ab的类型为A | B。初始化后的行为属于A类型(因为它只有A字段)并且在修改之后我希望开始充当类型B(因为它具有{{1}的所有字段1}})。

2 个答案:

答案 0 :(得分:1)

更新了答案

您已经澄清了您不需要交叉类型(请参阅下面的“原始答案”)。

因为您已将{a: 1}放入ab,编译器知道ab肯定包含A,其中没有b属性。显然,它不允许您通过向A添加B来将对象从b 转换为。

您可以改为创建一个新的B对象:

ab = {a: ab.a, b: 2};

The playground says编译器非常满意。

原始答案

联合类型适用于任何一种情况,例如当函数接受 字符串给定参数的数字时。我怀疑你正在寻找交集类型A & B,两者都是/),而不是联合类型(A | B,或者/或)(更多:{{3 }}):

interface A {
  a: number;
}

interface B extends A {
  b: number;
}

let ab: A & B = {
  a: 1,
  b: 0
};

ab.b = 2;

请注意,我已向对象初始值设定项添加了b属性,否则ab不是B

答案 1 :(得分:0)

分配了{ a: 1 }对象后,ab对象被typescript视为特定类型(A)的对象,只有属性 - a

在这种情况下

let ab: A | B = {
  a: 1
};

您正在分配A类型的defenitely对象,没有b属性。 而且转发器抛出错误

ab.b = 2;

它类似于你已经在相应的类型后卫if-brunch:

function f(ab: A | B) {
   if(ab instanceof A) {
       // You are here
       // There is no `b` property in this brunch
   }
   esle {
   }
}