类的联合数组(反之亦然)



我想要做到的是少重复自己,少犯错误。

我需要以下内容(是的,我需要两者):

const unionTypes = [GQLDualTaskState, GQLNumericTaskState];
type UnionType = GQLDualTaskState | GQLNumericTaskState;

正如你所看到的,我必须重复这些类,并且总是同时更改(例如添加或删除一个类)。

我找了很多,想自己找到一个解决方案,但没有。这似乎只适用于字符串:https://stackoverflow.com/a/45486495/1469540

我当前的步骤是:

type UnionTypeDef = [GQLDualTaskState, GQLNumericTaskState];
const unionTypes = [GQLDualTaskState, GQLNumericTaskState];
type UnionType = UnionTypeDef[number];

我理解语法Class['property']返回类Class的属性property的类型。但是为什么UnionTypeDef[number]的结果是一个联盟呢?

总结有两个问题:

  1. 如何解决具有类列表和相同类的联合的问题(我想了解解决方案)?
  2. 为什么UnionTypeDef[number]的结果是Union?

为什么UnionTypeDef[number]的结果是Union?

为什么不呢?

请看下面的注释,它解释了这里到底发生了什么。

class A { a: string = 'a' }
class B { b: string = 'b' }
// This is a type. It is tuple with a length of 2.
// index 0: a class A instance
// index 1: a class B instance
type UnionTypeDef = [A, B];
// This is a value. It is an array with a length of 2.
// index 0: the class A constructor
// index 1: the class B constructor
const unionTypes = [A, B];
// When you index an array or tuple by `number` you get a union of all possible
// values of all indices. In this case, `A | B`.
type UnionType = UnionTypeDef[number];

如何解决拥有类列表和相同类的并集的问题?

首先,你说这些是类。所以这意味着const unionTypes是类构造函数,而您将使用type UnionType作为实例?

如果是,您希望从常量元组[A, B, C]开始,而不是从类型开始。这是因为类型在运行时不存在,所以不能从类型创建值,但可以从值生成类型。

class A { a: string = 'a' }
class B { b: string = 'b' }
class C { c: string = 'c' }
const arrayOfConstructors = [A, B]; // only include A, and B
// Solution:
type UnionType = InstanceType<(typeof arrayOfConstructors)[number]>;
// UnionType can be instance of A or B
const instanceOfA: UnionType = new A()
const instanceOfB: UnionType = new B()
const instanceOfC: UnionType = new C() // Error: Type 'C' is not assignable to type 'A | B'.

工作原理:

typeof arrayOfConstructors

为了从值中获取类型,需要使用typeof操作符。这使它进入了类型土地。

(typeof arrayOfConstructors)[number]

要获得数组或元组中所有可能成员的并集,您可以按数字对其进行索引。所有数字键的所有可能值都作为联合返回。即['a', 'b'][number] //=> 'a' | 'b'

InstanceType<SomeClass>

当使用一个类作为类型时,typescript假定你指的是该类实例的类型。如果您指的是类构造函数,那么您可以使用typeof MyClass

所以const arrayOfConstructors = [A, B]创建了一个类构造函数数组,而不是实例数组。这意味着该值的类型实际上是[typeof A, typeof B]InstanceType从类类型中获取实例的类型

例如:(一个非常做作的例子)

type ABInstances = InstanceType<typeof A | typeof B> // type is A | B

所有这些都意味着,由于您有一个类构造函数的联合,您需要从它们中获取实例类型。


如果您经常使用该模式,您可以将其重构为:

interface Constructable { new(...args: any[]): any }
type InstanceUnion<T extends Constructable[]> = InstanceType<T[number]>

Constructable类型表示任何类的构造函数。它的定义使得它可以在InstanceUnion中使用约束,从而在您尝试传递字符串或普通对象时抛出类型错误。

InstanceUnion类型接受一个由类构造函数组成的数组或元组,获取其值的联合,然后获取该联合中所有成员的InstanceType

现在你可以:

type UnionType = InstanceUnion<typeof arrayOfConstructors>;
type OtherUnionType = InstanceUnion<typeof otherArrayOfConstructors>;

Playground和工作示例

最新更新