Osama Qarem
Osama Qarem

Reputation: 1459

How to achieve type inference for a reducer function concisely?

There are many examples on typing reducer functions, but they seem too verbose for my liking. I tried to keep it short and simple and wrote my actions and reducer typings as follows:

Actions

interface Actions {
  VISIBLE: "yes" | "no"
  LOCATION: { x: number; y: number }
}

Action

interface Action<T extends keyof Actions> {
  type: T
  payload: Actions[T]
}

Type intellisense for the payload perfectly for the following example:

const example : Action<'VISIBLE'> = {type: 'VISIBLE', payload: 'yes'}

However, in the following reducer function, even when the type of the action is clear, the type of the payload is not inferred as I expected:

const myReducer = (
  state: any,
  action: Action<keyof Actions>
) => {
  switch (action.type) {
    case 'VISIBLE':
      const example = action.payload
  }
}

I expected the type of example here to be inferred as 'yes' | 'no' but instead the inference is the union of the payloads of all actions:

type inference result for 'example' variable

What am I missing here in order to make payload type inference work?

Upvotes: 0

Views: 116

Answers (1)

ABOS
ABOS

Reputation: 3823

You can try

interface Actions {
  VISIBLE: "yes" | "no"
  LOCATION: { x: number; y: number }
}

interface Action<T extends keyof Actions> {
  type: T
  payload: Actions[T]
}

// Add custom typings here
type A = {
  [K in keyof Actions] : Action<K> 
}[keyof Actions]


const myReducer = (
  state: any,
  action: A
) => {
  switch (action.type) {
    case 'VISIBLE' :
      const example = action.payload
  }
}

Playground

Upvotes: 1

Related Questions