通过检查属性存在来推断减少的联合类型?

时间:2017-08-03 18:43:29

标签: typescript

我有一个非常大的联合类型,其成员具有多种类型且有一些重叠。实际上,这些都是真正大型数据库模式中的各种类型的记录属性。

    type A = { x: number; y: number }
    type B = { y: number; z: number }
    // many many more types

    type All = 
        | A 
        | B
        // many many more types

我有一个非常通用的函数,它接受任何类型并根据某些属性的存在做某事。问题是我无法检查是否存在属性,因为Typescript会抛出并且错误地说这个联合中的某些类型没有该属性。但理想情况下,我可以检查是否存在,而Typescript将根据该属性的存在推断出类型......

    function f(value: All) {
        if (value.x) {
            // value must be A or anything that has an x property
        } else if (value.y) {
            // value must be B or anything that has an x property       
        }
    }

任何想法如何使这项工作?

2 个答案:

答案 0 :(得分:3)

是的,你可以这样做:

type A = { x: number; y: number }
type B = { y: number; z: number }
type C = { z: number; x: number }
type D = { y: number; w: number }
type E = { w: number; z: number }
type All = A | B | C | D | E ;

function hasKey<K extends string>(key: K, val: any): val is {[P in K]: any} {
  return key in val;
}

function f(v: All) {
  if (hasKey('x', v)) {
    v // A | C
  } else if (hasKey('y',v)) {
    v // B | D
  } else {
    v // E
  }
}

hasKey函数是一个用户定义的类型保护,它将为您缩小工会范围。

答案 1 :(得分:0)

基于jcalz Answer,我更喜欢一种不需要专用库函数的方法:

type A = { x: number; y: number }
type B = { y: number; z: number }
type C = { z: number; x: number }
type D = { y: number; w: number }
type E = { w: number; z: number }
type All = A | B | C | D | E ;

function f(v: All) {
  if ('x' in v)) {
    v // A | C
  } else if ('y' in v)) {
    v // B | D
  } else {
    v // E
  }
}

我认为通过阅读可以更好地理解这种方法。