以类型安全的方式检查对象中的可能属性

时间:2017-01-26 02:36:42

标签: typescript typescript2.0

TypeScript 2.0支持这样的标记联合:

type Foo = {
  tag: 'foo'
  x: number
}

type Bar = {
  tag: 'bar'
  y: string
}

type FooOrBar = Foo | Bar

然后我们可以以类型安全的方式区分案例:

function doStuff(foobar: FooOrBar) {
  if (foobar.tag === 'foo') {
    console.log(foobar.x + 3)
  } else {
    console.log(foobar.y.length)
  }
}

一切都很好。但实际上tag字段并不是绝对必要的,以便区分这些类型。我们可以设想这样做:

type Foo2 = {
  x: number
}

type Bar2 = {
  y: string
}

type Foo2OrBar2 = Foo2 | Bar2

我是否有类似的方法可以以类型安全的方式对这样的联合进行案例分析?显而易见的事情不起作用:

function doStuff2(foobar: Foo2OrBar2) {
  if ('x' in foobar) {
    // Type error: Property 'x' does not exist on type 'Bar2'
    console.log(foobar.x + 5)
  } else {
    // Type error: Property 'y' does not exist on type 'Foo2'
    console.log(foobar.y.length)
  }
}

还有其他办法吗?

2 个答案:

答案 0 :(得分:2)

我想出了如何使用通用type guard

执行此操作
function hasKey<K extends string>(k: K, o: any): o is { [_ in K]: any } {
  return typeof o === 'object' && k in o
}

然后这个有效:

function doStuff2(foobar: Foo2OrBar2) {
  if (hasKey('x', foobar)) {
    console.log(foobar.x + 5)
  } else {
    console.log(foobar.y.length)
  }
}

<强>更新

有一个TypeScript票证可以使in作为类型后卫执行:

https://github.com/Microsoft/TypeScript/issues/10485

答案 1 :(得分:0)

您可以尝试这样的事情:

function doStuff2(foobar: Foo2OrBar2) {
    if ((<Foo2>foobar).x != undefined){         
    console.log((<Foo2>foobar).x + 5)
  } else {
    console.log((<Bar2>foobar).y.length)
  }
}