为什么从函数返回union类型时类型推断会丢失?

时间:2018-03-13 11:33:24

标签: typescript union-types

我使用以下联合类型:

interface A {
    type: 'A';
}

interface B {
    type: 'B';
    bProp: number
}

type X = A | B

当我尝试在数组中使用它并映射它时,我收到编译错误:

let list: X[] = []
let list2: X[] = list.map(el => {
    return true ? { type: 'B', bProp: 1 } : el
    }
)

(39,5): Type '(A | { type: string; bProp: number; })[]' is not assignable to type 'X[]'.
  Type 'A | { type: string; bProp: number; }' is not assignable to type 'X'.
    Type '{ type: string; bProp: number; }' is not assignable to type 'X'.
      Type '{ type: string; bProp: number; }' is not assignable to type 'B'.
        Types of property 'type' are incompatible.
          Type 'string' is not assignable to type '"B"'.

但是,当我将类型记录提取到局部变量并显式输入时,它可以工作:

let list: X[] = []
let list2: X[] = list.map(el => {
        let tmp: B = { type: 'B', bProp: 1 };
        return true ? tmp : el
    }
)

发生了什么事?

1 个答案:

答案 0 :(得分:1)

发生这种情况是因为当您使用字符串来初始化对象文字的字段时,字段的类型将被推断为string而不是字符串文字类型B,因此{ type: 'B' , bProp: 1 }输入为{ type:string, bProp: number },与B不兼容。

您可以明确地将字符串强制转换为字符串文字类型:

let list: X[] = []
let list2: X[] = list.map(el => {
    return true ? { type: 'B' as 'B', bProp: 1 } : el
})

第二个示例有效,因为您明确键入tmpB,因此编译器只检查对象文字是否与它不具有的B的声明类型兼容确定tmp的类型。这就是为什么这也有效:

let list2: X[] = list.map(el => {
    return true ? { type: 'B', bProp: 1 } as B : el
})
相关问题