I'm working on a project where I need to instantiate multiple copies of a particular class, but with different parameters. I'm creating a utility function withAlteredConstructorArgs to help me with this, but I'm having trouble getting the types quite right.
Here is an example of how I would like to use this utility:
const createCycler = withAlteredConstructorArgs(
Cycler,
function reverseElementArgs<T>(elements: Array<T>): [Array<T>] {
return [elements.reverse()];
}
);
const cycler = createCycler(['foo', 'bar', 'baz', 'quux']);
console.log(cycler.get(), cycler.get());
// > should log 'quux', 'baz'
The function I've written works as intended, but does not typecheck the way I expected. I have created a TypeScript Playground to fully demonstrate, but here is the implementation:
function withAlteredConstructorArgs<Args extends Array<any>, T>(
c: { new(...args: Args): T },
fn: (...args: Args) => Args
): (...args: Args) => T {
return (...args: Args) => new c(...fn(...args))
}
I recognize that I am not constraining T enough, and that's why I'm getting the error message: 'any[]' is assignable to the constraint of type 'Elements', but 'Elements' could be instantiated with a different subtype of constraint 'any[]'. I understand this error and have fixed it before, but not in a problem relating to class constructor arguments. What is the correct syntax for properly constraining the constructor parameters for T?
I recognize that I could probably work around this by creating a factory function and removing constructors altogether from the problem statement, but I feel as though understanding this approach would better improve my understanding of TypeScript in general. Also, I have hit similar issues with the factory approach, so it seems as though the constructor method would be the way to go anyways.