I've been delving into the world of implementing generic types in classes, but it seems that my understanding of what can and cannot be done with generics is a bit lacking.
Hopefully someone out there can shed some light on this for me!
My Objective
I have created a class designed to register tasks and execute them later based on their IDs. Each taskObject
consists of a taskId: string
and a callback function
callback: <R>(...args: any) => R
. Tasks are registered during class instantiation.
The main idea is to have type information about the return type of the callback function for each individual task.
Thus, taskId
is a literal type, and the callback
should be an arbitrary function where I want to infer the return type and then make this return type accessible within the class.
The Code Snippet
type Task<T extends string, V extends <R>(...args: any) => R> = {
taskId: T,
callback: V // <-- I'm aiming to resolve this
}
class Taskmanager<T extends string, V extends <R>(...args: any) => R> {
private callbacks = new Map<T, V>();
public constructor(tasks: Task<T,V>[]) {
tasks.forEach(task => {
this.callbacks.set(task.taskId, task.callback);
});
}
public runCallback(taskId: T) {
return this.callbacks.get(taskId)?();
}
}
This is just the initial step → now I have type hints for all registered taskIds
.
const tm = new Taskmanager([
{
taskId: "hello",
callback: () => "world" // <-- TS error: Type 'string' is not assignable to type 'R'
},
{
taskId: "circle",
callback: () => 360 // <-- TS error: Type 'number' is not assignable to type 'R'
}
]);
// Now I get type hints for `taskId` → "hello" | "circle"
const resHello = tm.runCallback("hello"); // <-- I expect: typeof resHello === "string" --> true
const resCircle = tm.runCallback("hello"); // <-- I expect: typeof resCircle === "number" --> true
Check out the TypeScript Playground link
Although I successfully limited the selection to only between hello
and circle
as parameters in runCallback
, I encountered TypeScript errors when declaring the callback functions in the class constructor.
// TS Error for taskId: "hello"
Type 'String' is not assignable to type 'R'.
'R' could take on any unrelated type that may not be a 'String'.
Is there a feasible way to automatically infer the return type of each callback function? Is this even achievable?
I did browse through several other questions and answers on StackOverflow, but unfortunately, I haven't been able to extract anything useful yet.
I apologize if this question seems trivial. Sometimes working with TS can definitely drive one crazy...
Thank you! 🙌