简体   繁体   中英

How can I reference to a type which is part of a union type, in TypeScript?

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'] ?

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; }

Playground

Distributive conditional types are automatically distributed over union types during instantiation. For example, an instantiation of T extends U ? X : Y T extends U ? X : Y with the type argument A | B | C A | B | C A | B | C for T is resolved as (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y) (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)

create a type which narrows your union:

type TypedAction<T extends Action['type']> = Extract<Action, {type: T}>

and then use like:

(action: TypedAction<"add">)

Playground Link

Reactor the branches of the Union out, so

type Add = {
  type: 'add',
  payload: number
};
...
type Action = Add | ...;
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM