Home > Mobile >  Typescript: How to convert map of 'typeof class' to map of class instances
Typescript: How to convert map of 'typeof class' to map of class instances

Time:12-20

I have an object map as follows:

const obj: {
    AddRowOperation: typeof RowOperations.AddRowOperation;
    DeleteRowOperation: typeof RowOperations.DeleteRowOperation;
    FilterRowsOperation: typeof RowOperations.FilterRowsOperation;
    ... 25 more ...;
    ResetRowStatusOperation: typeof RowOperations.ResetRowStatusOperation;
}

I want to map this object to instances of each class. So the type should be:

const obj: {
    AddRowOperation: RowOperations.AddRowOperation;
    DeleteRowOperation: RowOperations.DeleteRowOperation;
    FilterRowsOperation: RowOperations.FilterRowsOperation;
    ... 25 more ...;
    ResetRowStatusOperation: RowOperations.ResetRowStatusOperation;
}

I have tried a lot of options, but the type always ends up being unioned like:

const obj: {
    AddRowOperation: (RowOperations.AddRowOperation | RowOperations.DeleteRowOperation | ...);
    // etc...
}

I would have thought this was a simple scenario. It would be great to dynamically instantiate the classes rather than manually typing each one out.

Can this be done while keeping typescript happy? The classes do not share a common interface.

Edit

Solution proposed by jaclz:

type InstanceTypeProps<T extends Record<keyof T, new (...args: any) => any>> = { [K in keyof T]: InstanceType<T[K]> };

class A {}
class B {}
class C {}

const obj = { A, B, C }

type mapOfInstances = InstanceTypeProps<typeof obj>

Demo

CodePudding user response:

It looks like you want a mapped type over typeof obj where each property is transformed via InstanceType<T>, a utility type which uses conditional type inference to turn a construct signature type into that of the instances it constructs. Let's call this mapped type InstanceTypeProps<T>. You could write it like this:

type InstanceTypeProps<T extends Record<keyof T, new (...args: any) => any>> =
    { [K in keyof T]: InstanceType<T[K]> };

We're just applying InstanceType to each property T[K]. The only extra detail is that we have to constrain T to a type where each property is a construct signature. That looks like Record<keyof T, new (...args: any) => any>, meaning an object whose keys are whatever keys we want (it's really no constraint on the keys to say that T extends Record<keyof T, ...>) and whose values are assignable to new (...args:any) => any, a construct signature.

Let's make sure it works:

type MapOfInstances = InstanceTypeProps<typeof obj>;
/* type MapOfInstances = {
    AddRowOperation: RowOperations.AddRowOperation;
    DeleteRowOperation: RowOperations.DeleteRowOperation;
    FilterRowsOperation: RowOperations.FilterRowsOperation;
    //... 25 more ...;
    ResetRowStatusOperation: RowOperations.ResetRowStatusOperation;
} */

Looks good!

Playground link to code

  • Related