Reputation: 379
Here are the definitions I currently have:
interface Action<T extends string, P> {
type: T;
payload: P;
}
type ActionDefinitions = {
setNumber: number;
setString: string;
}
type ActionCreator<A extends keyof ActionDefinitions> =
() => Action<A, ActionDefinitions[A]>;
My thinking is that when I make an ActionCreator<any>
, any
must be constrained to a key of ActionDefinitions
. This is important because when I define a type like this:
type Creators = {
[K: string]: ActionCreator<keyof ActionDefinitions>
};
I need automatic type inference for each value in this object. So for example, if I were to define a Creators
object like this:
const testCreators: Creators = {
foo: () => ({
type: "setNumber",
payload: "string",
})
}
This should cause an error because foo
should be inferred to be an ActionCreator<"setNumber">
, which should be of type Action<"setNumber", number>
, and therefore the payload
should be a number, not a string.
However, TypeScript simply allows payload
to be of any type, which seems wrong because if the generic type A
is equal to "setNumber", then foo
should have to return Action<"setNumber", ActionDefinitions["setNumber"]>
, i.e., Action<"setNumber", number>
...but it allows any
instead of number
.
Anyone know why this is or how I can fix it?
Upvotes: 1
Views: 64
Reputation: 8370
The problem is keyof ActionDefinitions
is a union type and passing it into ActionCreator
you eventually get type:
type ActionCreator = () => Action<keyof ActionDefinitions, string | number>
That allows string | number
as a payload.
What you really need is to iterate over keys of keyof ActionDefinitions
and pass concrete keys into ActionCreator
:
type Creators = {
[K: string]: { [I in keyof ActionDefinitions]: ActionCreator<I> }[keyof ActionDefinitions]
};
updated with a bit more generic version of ActionCreator
type:
type ActionCreator<T, K extends Extract<keyof T, string> = Extract<keyof T, string>> = {
[I in K]: () => Action<I, T[I]>;
}[K]
type Creators = {
[K: string]: ActionCreator<ActionDefinitions>
};
Upvotes: 1