Issue with strong typing in Typescript
I have the following code:
export type FooParams = {
foo1: { x: number };
foo2: { y: string };
};
export type FooKey = keyof FooParams; // or export type FooKey = "foo1" | "foo2";
export interface FooAction<T extends FooKey> {
execute: (params: FooParams[T]) => void;
}
const foo1Action: FooAction<"foo1"> = {
execute: (params) => {
console.log(params.x);
},
};
const foo2Action: FooAction<"foo2"> = {
execute: (params) => {
console.log(params.y);
},
};
export const fooActions: Record<FooKey, FooAction<FooKey>> = {
foo1: foo1Action,
foo2: foo2Action,
};
I can't strongly type the variable fooActions
, in order to force a FooAction
for every FooKey
. In the above example I have the following error.
Type 'FooAction<"foo1">' is not assignable to type 'FooAction<keyof FooParams>'.
Type 'keyof FooParams' is not assignable to type '"foo1"'.
Type '"foo2"' is not assignable to type '"foo1"'.ts(2322)
Any idea how to correctly declare the fooActions
type?
FooAction<FooKey>
means execute
will have type (params: FooParams[FooKey]) => void
which in turns would resolve to (params: { x: number } | { y: string }) => void;
. This means it will have to be a function that handle both { x: number }
and { y: number }
. So all values of an object of type Record<FooKey, FooAction<FooKey>>
would have to handle both types, while foo1Action
and foo2Action
can only handle one type or the other.
You want to type fooActions
with a correlation between the key and the type. You can do that with a custom mapped type:
type FooActionMap = {
[P in FooKey]: FooAction<P>
}
export const fooActions: FooActionMap = {
foo1: foo1Action,
foo2: foo2Action,
};
Playground Link