无法从联合类型访问参数(TypeScript)

时间:2016-08-24 15:54:49

标签: javascript typescript

为什么无法访问联合类型中的属性,如下所示:

export interface ICondition {
  field: string
  operator: string
  value: string
}

export interface IConditionGroup {
  conditions: ICondition[]
  group_operator: string
}

function foo(item: ICondition | IConditionGroup) {
  if(typeof item.conditions === "undefined") { // does not work
    let field = item.field; // does not work
    ///.. do something 
  } else {
    let conditions = item.conditions; // does not work
    /// .. do something else
  }
}

我收到这些错误:

error TS2339: Property 'conditions' does not exist on type 'ICondition | IConditionGroup'.
error TS2339: Property 'conditions' does not exist on type 'ICondition | IConditionGroup'.
error TS2339: Property 'field' does not exist on type 'ICondition | IConditionGroup'.

但我必须投射类型才能让它发挥作用 - 就像这样:

function foo2(inputItem: ICondition | IConditionGroup) {
  if(typeof (<IConditionGroup>inputItem).conditions === "undefined") {
    let item= (<ICondition>inputItem);
    let field = item.field;
    ///.. do something 
  } else {
    let item= (<IConditionGroup>inputItem);
    let conditions = item.conditions;
    /// .. do something else
  }
}

据我所知,JS中的类型信息丢失了,为什么我必须在TS中明确地转换它?

1 个答案:

答案 0 :(得分:4)

Typescript使用Type Guards来处理这个问题,通常它就像:

一样简单
if (typeof item === "string") { ... } else { ... }

或者

if (item instanceof MyClass) { ... } else { ... }

但是在您使用不可能的界面时,您需要创建自己的User-Defined Type Guards

function isConditionGroup(item: ICondition | IConditionGroup): item is IConditionGroup {
    return (item as IConditionGroup).conditions !== undefined;
}

function foo(item: ICondition | IConditionGroup) {
    if (isConditionGroup(item)) {
        let conditions = item.conditions;
        // do something
    } else {
        let field = item.field;
        // do something else
    }
}

code in playground

你也可以在没有防护装置的情况下做到这一点:

function foo(item: ICondition | IConditionGroup) {
    if ((item as IConditionGroup).conditions !== undefined) {
        let conditions = (item as IConditionGroup).conditions;
        // do something
    } else {
        let field = (item as ICondition).field;
        // do something else
    }
}

但是这需要详细说明,因为你需要输入断言item 3次而不是一次。