As TypeScript does not currently support variadic types, I am exploring alternative methods to achieve the desired functionality. I am developing a library and am willing to take extra steps to simplify the process for end users.
Below is some simplified pseudocode:
type ConstructorBase<T> = {
new (id: number): T;
type: string
}
type Things = { [key: string]: Thing }
private _things: Things
getThings (id: number, ...ctors: ConstructorBase<Thing>): Thing[] {
return ctors.map((ctor) => this._things[ctor])
}
The current approach involves users passing specially crafted constructors to retrieve instances associated with an id. While this method works well, users have to cast the obtained thing array to the expected outcome.
const [a, b] = get(15, ThingTypeA, ThingTypeB) as [ThingTypeA, ThingTypeB]
const [c, d, e] = get(15, ThingTypeC, ThingTypeD, ThingTypeE) as [ThingTypeC, ThingTypeD, ThingTypeE]
My goal is to eliminate the need for as ...
in user code and rely on TypeScript to infer the types automatically.
I envision something like this:
getThings <T extends Thing[]> (id: number, ...ConstructorBase<T>): infer[]
Experiments
I have experimented with various alternatives and explored discussions on TypeScript issues related to this topic but have yet to find a solution. My attempts at using overloads seem limited by the requirement of consistent return types, whereas I need to handle variable-length tuples. The system only recognizes the shortest implementation rather than the longest one.
getThing <T, U> (id: number, t1: ConstructorBase<T>, t2?: ConstructorBase<U>): [T, U?]
getThing <T, U, V> (id: number, t1: ConstructorBase<T>, t2?: ConstructorBase<U>, t3?: ConstructorBase<V>): [T, U?, V?] {
// implementation
}
Considering that the scenario of exceeding six things is highly unlikely, I am open to providing overrides if necessary. However, despite my efforts, I have been unable to make it work.
Any assistance provided would be greatly appreciated!