In TypeScript, I've defined a helper function called create that takes a constructor and the constructor's typed arguments to create a new instance of a class:
function create<Ctor extends new (...args: any[]) => any, R extends InstanceType<Ctor>>(
ctor: Ctor,
...args: ConstructorParameters<Ctor>
): R {
return new ctor(...args)
}
This works for simple classes like so:
class Bar {
constructor(param: number) { }
}
const bar1 = create<typeof Bar, Bar>(Bar, 1);
// Compile error: Argument of type '"string"' is not assignable to parameter of type 'number'.ts(2345)
const bar2 = create<typeof Bar, Bar>(Bar, 'string');
However, if I have a generic class, I can't get TypeScript to perform the proper type checking on create:
class Foo<T> {
constructor(param: T) { }
}
// Ok
const foo1 = create<typeof Foo, Foo<number>>(Foo, 1);
// This should be an error but is not
const foo2 = create<typeof Foo, Foo<number>>(Foo, { not: 'a number' })
The root cause is that signature of create in the second case takes an unknown parameter:
Main question
Is it possible to explicitly write out the type of the generic class constructor in the call to create without inlining the type itself and while still preserving the signature of create?
Attempts
My first thought was:
create<typeof Foo<number>, Foo<number>>(Foo, { not: 'a number' })
But that is invalid code.
So far, the best workaround I've found is to use a temporary class to explicitly capture the constructor type:
class Temp extends Foo<number> { }
// This correctly generates an error
create<typeof Temp, Foo<number>>(Foo, { not: 'a number' });
Can this be done in a more elegant way?

Foo<number>then you can annotate that and see an error if you don't pass the right thing, like this.