Description
I'm on TypeScript 3.1, and @bterlson asked if there was a way to construct all constructors inside of an array. However, trying to do this in a way that worked for object properties as well as array-likes seems impossible
type ConstructAll<T> = {
[K in keyof T]: InstanceType<T[K]>
};
type Foo = ConstructAll<[typeof Date, typeof RegExp]>;
This gives an error on the first type argument to InstanceType
:
[ts] Type 'T[K]' does not satisfy the constraint 'new (...args: any[]) => any'.
Ugh. Okay, fine.
type AnyConstructor = new (...args: never[]) => unknown;
type ConstructAll<T extends Record<string, AnyConstructor>> = {
[K in keyof T]: InstanceType<T[K]>
};
type Foo = ConstructAll<[typeof Date, typeof RegExp]>;
Which gives me an error on the first type argument to ConstructAll
:
[ts]
Type '[Date, RegExp]' does not satisfy the constraint 'Record<string, new (...args: any[]) => any>'.
Index signature is missing in type '[Date, RegExp]'.
I'll save you time; the following doesn't work either:
type AnyConstructor = new (...args: never[]) => unknown;
type ConstructAll<T extends AnyConstructor[] | Record<string, AnyConstructor>> = {
[K in keyof T]: InstanceType<T[K]>
};
type Foo = ConstructAll<[typeof Date, typeof RegExp]>;
You end up with the original scenario. I end up not being able to reuse InstanceType
at all because it has a constraint that we can't dive into. I have to instead use some unconstrained conditional type.
type Constructor<T> = new (...args: any[]) => T;
type ConstructAll<T extends Constructor<unknown>[] | Record<string, Constructor<unknown>>> = {
[K in keyof T]: T[K] extends Constructor<infer T> ? T : never;
};
type Foo = ConstructAll<[typeof Date, typeof RegExp]>
It seems problematic that we didn't want to "split the world" into array mapped types and object mapped types, but you end up with that problem anyway in some cases.