Here I have three functions and I put them into a literal:
type AnyCallback = (...args: any) => unknown;
const callbackAlpha = (data: string) => {
console.log(data);
return data.length;
};
const callbackBeta = (data: string, prefix: string) => {
console.log(data, prefix);
return prefix + data;
};
const callbackGamma = (data: string, prefix: string, suffix: string) => {
console.log(data, prefix, suffix);
return prefix + data + suffix;
};
let allCallBack: Record<string, AnyCallback> = {
callbackAlpha,
callbackBeta,
callbackGamma,
};
and then, I want to define an array type to record the function name and parameters when I call it, the member supposed to be like this:
{
name: //name of a function in the literal
args: //parameters that needed when I call the function
}
Firstly, I tried like this:
type TaskType = keyof typeof allCallBack;
type TaskQueue = {
name: TaskType;
args: Parameters<(typeof allCallBack)[TaskType]>;
}[];
Obviously, it is wrong, because you can give "name" any string value,and "args" can be any parameters of the three functions.
In TypeScript, when you assign/alias a subtype (a more specific type / narrow type) to a supertype (a less specific type / broader type), the subtype is not preserved in the supertype.
For example,
The same thing has happened to your functions when you assign subtypes
"callbackAlpha",(data: string) => numberto its corresponding supertypes -string, and(...args: any[]) => anyas defined inRecord<string, AnyCallback>If you want TS to preserve the exact type information, then removing the type declaration (
Record) forallCallbackwould help -Here, the type inference works just fine and the exact types are preserved. And then, to construct the
TaskQueuetype preserving the relation/association between the name and args, it can be done using generics -For example,
TS Playground link