Reputation: 198238
I defined a union type for actions in TypeScript:
type Action = {
type: 'reset',
} | {
type: 'add',
payload: number
} | {
type: 'minus',
payload: number
}
In some functions, I want to reference to a part of the union type, like:
function handleAdd(state: State, action: {
type: 'add',
payload: number
}): State => {
// handle the add
}
Is there a way to simplify the typing of action
so I don't need to repeat the full definition of
{
type: 'add',
payload: number
}
here?
Update:
I don't want to predefine each action type separately. Is there another solution, like Action[type='add']
?
Upvotes: 5
Views: 1534
Reputation: 42188
create a type which narrows your union:
type TypedAction<T extends Action['type']> = Extract<Action, {type: T}>
and then use like:
(action: TypedAction<"add">)
Upvotes: 3
Reputation: 37938
This can be achieved relying on distributive conditional types:
type ExtractType<T extends Action['type'], A = Action> =
A extends { type: T } ? A : never;
type Add = ExtractType<'add'>; // { type: 'add'; payload: number; }
Distributive conditional types are automatically distributed over union types during instantiation. For example, an instantiation of
T extends U ? X : Y
with the type argumentA | B | C
forT
is resolved as(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)
Upvotes: 6
Reputation: 1804
Reactor the branches of the Union out, so
type Add = {
type: 'add',
payload: number
};
...
type Action = Add | ...;
...
Upvotes: 1