1

I want to create a function called createInstance that receives an instance a and creates a new instance c that is of the same type as a. Note that inside of createInstance I do not know what is the type of a, I only know it inherits from some class A. But I want c to be of type B, which is the real type of a. This is what I've got so far:

class A {
    constructor(public ref: string) {}
}

class B extends A {
}

const createInstance = (a: A): void => {
    const t = a.constructor
    const c = new t("c")
    console.log(c)
    console.log(c instanceof B)
}

const b = new B("b")
createInstance(b)

I've tried it in the typescript playground and it works, I get true for c instanceof B. But it shows a warning in the new t("c") line, that says: "This expression is not constructable. Type 'Function' has no construct signatures."

What is the correct way to do this? Thanks

2
  • 1
    You want to do this...why? How is it supposed to know what arguments to pass to the constructor? If you have A in scope to type the argument, why not just call new A directly? This doesn't really make any sense. Commented Apr 26, 2020 at 16:47
  • @JaredSmith The code I shared is a minimal example of the problem. It does not illustrate the usage. I have A in scope but I don't want c to just be of type A, I want it to be of the same type as b. In this case, B. But I can't know inside of createInstance which type of instance to create, I just know it should be a subclass of A and the same type as a. Commented Apr 26, 2020 at 19:03

2 Answers 2

5

This actually is still a missing feature in TypeScript, since T.constructor is not of type T but just a plain function. You can force-cast it:

const t = a.constructor as { new(ref: string): A };

Edit: you can have the constructor already typed (parameters list) using ConstructorParameters:

const t = a.constructor as { new(...args: ConstructorParameters<typeof A>): A };

See a relative issue on TS repository#4536 and this similar question

Playground Link

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

6 Comments

microsoft/TypeScript#3841 has more relevant discussion about this; the feature is missing because it's not clear how to add it in any useful or safe way. What stops someone from writing class C extends A { constructor(oops: number) { super(oops.toFixed()); } }? new C(123).constructor is incompatible with new A("").constructor, so assuming a.constructor is new (ref: string) => A is unsafe, and that's why it needs a type assertion
Sure, thank you jcalz for the clear example. My answer assumes OP is knowing what he is doing
Thanks! Is there a way to get new(ref: string) out of A? I don't want to duplicate its parameter list
Yes, I think you can do it with ConstructorParameters<A>. Updated the answer
@leonardfactoryt Thank you! How about const t = a.constructor as typeof A? I checked and it works. Since it's shorter, I guess it's better?
|
0

This works:

const t = a.constructor as typeof A;

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.