In the process of developing this class, found at this playground link:
export class CascadeStrategies<
T extends Record<any, (...args: any[]) => unknown>
> {
private strategies: T = {} as T;
constructor(strategyMap: T) {
this.registerStrategies(strategyMap);
}
private registerStrategies(strategyMap: T) {
this.strategies = strategyMap;
}
use(
strategies: (keyof T)[],
...args: Parameters<T[keyof T]>
): ReturnType<T[keyof T]> {
return this.strategies[strategies[0]](...args);
}
}
The intended functionality of this class should be
const myMap = {
test: (arg1: number, arg2: string) => arg1,
otherTest: (arg1: number, arg2: string) => arg2,
thirdTest: (arg1: number, arg2: string) => null
}
const cascadeStrats = new CascadeStrategies(myMap);
const shouldBeNumber = cascadeStrats.use(["test"], 0, "");
const shouldBeString = cascadeStrats.use(["otherTest"], 0, "");
const shouldBeNull = cascadeStrats.use(["thirdTest"], 0, "");
The goal is to have T
represent an object where each entry is a function that can accept the same parameters and return a string
. This is achieved by using
T extends Record<any, (...args: unknown[]) => string
. However, there is an issue with the typing, as this.strategies[strategies[0]](...args)
results in type unknown
, which does not match the expected ReturnType<T[keyof T]>
.
If the type of strategies
is changed from T
to Record<any, any>
, then
this.strategies[strategies[0]](...args)
will have the correct type and be inferred correctly when used. Although strategies
is only an internal variable and does not impact user experience when using the class, it raises the question of what needs to be adjusted to achieve the desired outcome:
- Accurate inference while utilizing the user-defined
strategyMap
(an object with functions that share the same parameters and returnstring
). strategies
not having a type ofRecord<any, any>
.- When the user employs
cascadeStrats.use
, they receive accurate inferences regarding the function's arguments and return type.