I am trying to get typescript generic to work when it is being used to access an object's property dynamically (inside square brackets).
**Minimal Example : **
export type TaskType = 'withdraw' | 'pickup'
interface Task<T extends TaskType = TaskType> {
val: number
}
interface Memory {
tasks : {
[T in TaskType] : {
[targetId: string]: Task<T>
}
}
}
const data: Memory = {
tasks : {
withdraw : {
'a' : {val: 0}
},
pickup : {
'a' : {val: 0}
}
}
}
const res1 = data.tasks.withdraw.a; // Type is set correctly to Task<"withdraw">
let fn = function<T extends TaskType>(taskType: T) {
const res2 = data.tasks[taskType].a;
// ^ Type here is not being infered. It is Task<"withdraw"> | Task<"pickup">
};
As you can see in the above example when called outside the function with a specific key res1 returns the correct type.
But when using a variable data.tasks[taskType].a; it dosent work. Type of res2 should be Task<T>, instead it is something else. What am I doing wrong ?
UPDATE : More Info
I feel like I should expand a bit more on what my actual problem is. The actual Task interface does not overlap between different TaskTypes. Also I have a function like the one shown below.
interface Task<T extends TaskType = TaskType> {
val: number
resourceType: T extends 'withdraw' ? string : undefined
}
...
let claim = <T extends TaskType>(taskType: T, task: Task<T>) => {
data.tasks[taskType].a = task; // Why is task not assignable here ?
}
Since Task<T> between various string do no have the same properties, the line data.tasks[taskType].a = task; throws an error.
I am calling the claim function like so :
const pickupTask = {val: 0, resourceType: undefined} as Task<`pickup`>;
claim('pickup', pickupTask) // The function will always be called with the same tasktype i.e. calling claim('withdraw', pickupTask) should throw an error
Logically speaking the parameter pickupTask should be able to be assigned to data.tasks[taskType].a since taskType='pickup'. So why is it throwing an error ? I might have misunderstood typescript generics, but I am not sure where I am wrong.
Also I cannot change Memory interface to be a generic interface.
Task<withdraw> | Task<pickupbecause T iswithdraw|pickup. It's not enforced to be a specific one.Tshould be what ever string is passed to the function. and henceresshould beTask<T>. If not how do I achieve this ?Type here is not being infered??taskTypeis of typeT. I expectres2to be of the typeTask<T>res2is distributed over the union