The compiler is having difficulty handling the concept of "correlated union types" as discussed in ms/TS#30581. However, there is a suggested workaround provided officially in ms/TS#47109, which involves using a map type that acts as the single source of truth for functions and dispatch arguments.
Let's define this map type:
type ActionMap = {
a: {
payload?: {};
};
b: {
payload?: {};
};
};
Assuming that you are working with redux
actions, I have incorporated an optional payload property.
Now, we can type hh
utilizing this type along with mapped types:
const hh: {
[K in keyof ActionMap]: (action: ActionMap[K] & { type: K }) => string;
} = {
a: (action) => '',
b: (action) => '',
};
We will also create another type for the dispatch arguments, where we return a default union along with specific arguments based on the generic argument representing the dispatched action:
type DispatchArgs<T extends keyof ActionMap = keyof ActionMap> = {
[K in T]: { type: K } & ActionMap[K];
}[T];
Example of usage:
export function dispatch<ActionType extends keyof ActionMap>(
arg: DispatchArgs<ActionType>,
) {
const h = hh[arg.type];
h(arg); // no error
}
Link to Playground