Today I Learned

Generic with class as argument and returning instance

So let’s imagine you have few classes. Let’s say it’s just something like

class Foo {};
class Bar {};
class Baz {};

You want to create a function that accepts a class as an argument and based on that, it returns class instance.

The best approach would be to have TS generics.

function create<T>(model: T): T {
    // Error!
    // This expression is not constructable.
    // Type '{}' has no construct signatures.
    return new model();
}

If we use it like that, we’ve got an error that type doesn’t have construct signatures.

Why is that?

It’s because, when you are defining some variable or agument to be type of a class, what you actually mean is that this variable needs to be instance of given class!

So how can we tell typescript that we want class constructor?

We can tell typescript that argument (or variable) needs to be class constructor using new () => Type or { new(): Type }

function create<T>(model: new () => T): T {
    return new model();
}


create(Foo); // returns Foo instance
create(Bar); // returns Bar instance
create(Baz); // returns Baz instance

However, there is one catch here! new () needs to have the same signature as class constructor, otherwise it will throw an error as well

class Foo {
    constructor(a: number) {
    }
}

create(Foo); // Error!

You can also work around it by having

new (...args: any[]) => T

…that is if you don’t care about constructor arguments much… ;)