我想要做到的是少重复自己,少犯错误。
我需要以下内容(是的,我需要两者):
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]
的结果是一个联盟呢?
总结有两个问题:
- 如何解决具有类列表和相同类的联合的问题(我想了解解决方案)?
- 为什么
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和工作示例