Reputation: 3209
If I have an object of type that take a generic T that extends another interface/type. How can I type an object/method param to allow any subtype generic.
An exemple will be easier to understand:
type Options = {
id: string;
};
type Task<O extends Options = Options> = {
start: (options: O) => void;
};
const t1: Task<Options> = {
start: ({ id }) => {
console.log(id);
}
};
const t2: Task<{ id: "static"; foo: true } & Options> = {
start: ({ id, foo }) => {
console.log(id, foo);
}
};
const TaskManager = {
registerTask: (task: Task) => { // maybe I miss something here, I would like to avoid Task<any>
// use task
}
};
TaskManager.registerTask(t1); // Ok
TaskManager.registerTask(t2); // ERROR: Argument of type 'Task<{ id: "static"; foo: true; } & Options>' is not assignable to parameter of type 'Task<Options>'.
How can I modify registerTask to allow any Task
that accept Task<T extends Options>
Can someone help me to fix this typing issue ?
EDIT: Also, If TaskManager store an array of Task, how to type this array with generics ?
class TaskManager {
private static tasks: Task[] = [];
public static registerTask = <O extends Options>(task: Task<O>) => {
TaskManager.tasks.push(task); // ERROR: Argument of type 'Task<O>' is not assignable to parameter of type 'Task<Options>'
};
}
I need to provide generic at class level ?
Temporary solution is to declare an array of Task<any>
:
private static tasks: Task<any>[] = [];
to allow any subtypes.
Upvotes: 2
Views: 1061
Reputation: 327994
You can make TaskManager.registerTask()
a generic method like this:
const TaskManager = {
registerTask: <O extends Options>(task: Task<O>) => {
}
};
which will then cause the compiler to infer O
when you call it:
TaskManager.registerTask(t1); // okay
// (property) registerTask: <Options>(task: Task<Options>) => void
TaskManager.registerTask(t2); // okay
// (property) registerTask: <{ id: "static"; foo: true; } & Options>(
// task: Task<{ id: "static"; foo: true; } & Options>
// ) => void
Upvotes: 2