1

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

3
  • 1
    Could you provide a minimal reproducible example that can be pasted into a standalone IDE like The TypeScript Playground (link here!) to demonstrate the issue you're seeing? I could suggest something like InstanceTypeProps from the link, but without a testable example it's hard to tell. If that works for you I could potentially come up with my own example code for the answer, but ideally it would be in the question itself. Commented Dec 19, 2021 at 22:07
  • @jcalz yep, that's done the trick. typescriptlang.org/play?#code/… Commented Dec 19, 2021 at 22:25
  • post an answer I can upvote and accept. Commented Dec 19, 2021 at 22:26

1 Answer 1

2

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.