从其他属性确定属性的类型

时间:2019-09-25 16:30:19

标签: typescript discriminated-union

在类中,我知道一个属性将是基于另一个属性的有区别的联合之一,但是我不知道如何使TypeScript反映出来。

我尝试扩展如下所示的有区别的联合,但这是行不通的。

type A = { thing: 1, otherThing: string }
type B = { thing: 2, otherThing: number }
type C = A | B;

// ERROR: A class can only implement an object type or intersection
// of object types with statically known members. ts(2422)
class C implements C {
  // ...
}

该方法有效,但是这个问题是看我是否可以使它用吸气剂代替方法。

class Example {
  thing: 1 | 2;

  get otherThing() {
    if (this.thing === 1) return 'one';
    return 2;
  }

  getOtherThing(thing: 1): string;
  getOtherThing(thing: 2): number;
  getOtherThing(): string | number {
    if (this.thing === 1) return 'one';
    return 2;
  }

  constructor(value: Example['thing']) {
    this.thing = value;
  }

  fails() {
    // I'd really like this type of logic to work
    if (this.thing === 1) {
      // Type '2 | "one"' is not assignable to type 'string'.
      const test: string = this.otherThing;
    }
  }

  works() {
    if (this.thing === 1) {
      const test: string = this.getOtherThing(this.thing);
    }
  }
}
  

编辑:具体来说,此问题是在同一类中使用的。 solution provided by @jcalz非常好,如果我无法找到想要的结果,那么我可以将其与组成结合使用以达到相似的结果。

1 个答案:

答案 0 :(得分:0)

单个类或接口无法扩展或实现事物的并集,因此无法直接实现您想要的东西。如果您真的需要一个类来给您像被歧视的联合一样的行为,我会考虑使用一个generic类,其中您的依赖属性为conditional type

class Example<T extends C["thing"]> {
  constructor(
    public thing: T,
    public otherThing: Extract<C, { thing: T }>["otherThing"]
  ) {}
}

在判别属性thing是有效键类型(并且1 | 2有效)的特定实例中,您可以使用mapped types代替条件类型(尽管我将使用映射出像这样的条件类型):

type MappedOtherThing = {
  [K in C["thing"]]: Extract<C, { thing: K }>["otherThing"]
};

class Example<T extends C["thing"]> {
  constructor(public thing: T, public otherThing: MappedOtherThing[T]) {}
}

Extract<C, {thing: T}>["otherThing"]使用Extract实用程序类型查找可分配给C的{​​{1}}成员,然后looks up为其{{1} }属性。

这些实现中的任何一种都会给您以下行为:

{thing: T}

希望有帮助。祝你好运!

Link to code