In typescript, a factory function can be created like this, with a return type defined:
function factory1<T>(object: new () => T): T {
return new object();
}
If I want to create several different objects, I can extend this function to:
function factory2<T, U>(object1: new () => T, object2: new () => U): [T, U] {
return [new object1(), new object2()];
}
Now to my question: Can this factory pattern be generalized to take any number of unrelated object types and still return a typed tuple? Or is the only option to drop the strong typing and revert to using any?
Something like this:
function factory3<T extends any[]>(...objects: {new(): any}[]): [...T] {
// BODY
}
The issue with the last one, factory3, is that we lose the type of T and instead get "typeof T". For example:
factory3(ClassA, ClassB, ClassC);
// actually becomes this:
factory3<typeof ClassA, typeof ClassB, typeof ClassC>(...) : [typeof ClassA, typeof ClassB, typeof ClassC] {}
// But we want this to happen instead, which is possible for factory 1:
factory3<typeof ClassA, typeof ClassB, typeof ClassC>(...) : [ClassA, ClassB, ClassC] {}
Sure, you can make the factory rest argument a mapped array/tuple type. You'll need a type assertion or something like it to convince the compiler that the returned value in the body is really a [...T]:
function factory<T extends any[]>(...ctors: { [K in keyof T]: new () => T[K] }) {
return ctors.map(x => new x) as [...T];
}
You can verify that this works:
class A {
x = 1;
}
class B {
u = "u";
}
class C {
s = true;
}
const objects = factory(A, B, C);
// const objects: [A, B, C]
console.log(JSON.stringify(objects)); // [{"x":1},{"u":"u"},{"s":true}]
Playground link to code
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With