Generic typing of callback functions in classes

This is a follow up from my last post Generic types in classes which has been perfectly answered by @jcalz. Since playing around with this solution, I highly doubt my understanding of Typescript in general. I simply can’t get my head around of what is going on and why certain things “are not working”.

However, I recently wanted to know how I could achieve a typed mapping of taskIds to their callback back functions and get a typed result. See here. I have now extended the code to

type Values<T extends string> = {[K in T]: any}
type Results<T extends string, R> = {[K in T]: R}
type Callback<T extends string> = (prev?: any, values?: Values<T>) => any


type Task<
  K extends string,
  V extends Callback<K>
> = {
  taskId: K;
  callback: V;
};


class Taskmanager<
  S extends string,
  const T extends Task<
    S,
    Callback<S>
  >
> {

  private prevTaskId?: T["taskId"];
  private values!: Values<T["taskId"]>;
  private tasks = new Map<T["taskId"], T>


  public constructor(tasks: readonly T[]) {
    tasks.forEach((task) => {
      this.tasks.set(task.taskId, task);
      this.values = {...this.values, [task.taskId]: undefined};
    });
  }


  public run<K extends T["taskId"]>(): {[ID in K]: ReturnType<Extract<T, { taskId: ID }>["callback"]>} {
    let result = {}

    this.tasks.forEach(task => {
      const prev = this.prevTaskId ? this.values[this.prevTaskId] : undefined;
      const res = task.callback(prev, this.values);
      this.values[task.taskId] = res;
      this.prevTaskId = task.taskId;
      result = {...result, [task.taskId]: res};
    })

    // Is there a better way than casting the return type?
    return result as {[ID in K]: ReturnType<Extract<T, { taskId: ID }>["callback"]>};
  }
}

// ---------------
//  TEST
// ---------------
const tm = new Taskmanager([
  {
    taskId: "defineValue",
    callback: (prev, values) => {
      return 1;
    },
  },
  {
    taskId: "usePrev",
    callback: (prev) => {
      return "hello " + prev;
    },
  },
  {
    taskId: "useValue",
    callback: (prev, values) => {
      // How could I achieve type hints for `values`? Currently values: { [x: string]: any }
      // eg. values?.defineValue or values?.useValue
      // Since I have return types from the callback functions, could I also infer those? E.g. typeof values?.useValue === 'object' --> true
      return {
        prev: prev,
        usePrevVal: values?.usePrev
      }
    },
  }
]);

const results = tm.run();
// results → { defineValue: number, usePrev: string, useValue: { prev: any, useDefineVal: any } } --> this is perfect!

console.log("Results", results)
// LOG → "Results", { "defineValue": 1, "usePrev": "hello 1",  useValue: { "prev": "hello 1", "useDefineVal": 1 }} --> works as intended

Here’s a link to TS Playground

How could I get type hints for the callback values parameter? Preferably including the return type of the associated callback but having the taskIds as keys would already be good enough.

Thanks!