15

Using typescript 3.7, I have an interface with a property that is meant to accept a constructor function:

interface IConstruct<T> {
  type: new (...args:ConstructorParameters<T>) => T;
}

My thought is that IConstruct<User> will have a property {type: User}.
But the compiler tells me that T cannot be used there. Why is that?

TS2344: Type T does not satisfy the constraint 'new (...args: any) => any'

0

2 Answers 2

10

The type of ConstructorParameters looks like this:

type ConstructorParameters<T extends new (...args: any) => any> =
  T extends new (...args: infer P) => any ? P : never;

So type parameter T itself has to extend some sort of constructor function defined by the constraint extends new (...args: any) => any. Write above example like this and you should be good to go:

class User {
    constructor(public name: string) { }
}

// add constructor function type constraint for T
interface IConstruct<T extends new (...args: any) => any> {
    // we can use built-in InstanceType to infer instance type from class type
    type: new (...args: ConstructorParameters<T>) => InstanceType<T>;
}

type UserConstruct = IConstruct<typeof User>

const constr: UserConstruct = {
    type: User
}

constr.type // new (name: string) => User

const userInstance = new constr.type("John") // userInstance: User

console.log(userInstance.name) // John

Playground

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

5 Comments

Thanks for the tip. How come when you declared your type T1 you used typeof User instead of just User ? Isn't User already a type?
@BeetleJuice Not quite, there is a difference: User is the type of the instance, typeof User is the actual class type. Here is a good example in the docs.
@BeetleJuice Updated the answer to return the instance type of T when invoking IConstruct.type constructor function (that is probably what you want here). I also gave a bit more details to the example, hope it helps.
In the type definition of ConstructorParameters, what is ? P : never? Is never a reference to a constructor that is never executed - i.e., the constructor signature of an abstract class?
@CraigHicks No, the ? : construct is a conditional type, never the bottom type in the type system. That means nothing is assignable to it, so you can use it here as some kind of type error indication, if TS is not able to infer the constructor parameters.
2

The Problem has been resolved: https://github.com/microsoft/TypeScript/issues/31278

For me the missing typeof was the problem:

class Parent<T> {
    constructor(readonly data: T) {
    }
}
class Child<T> extends Parent<T> {
    constructor(...args: ConstructorParameters<typeof Parent<T>>) {
        super(...args);
    }
}

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.