简体   繁体   中英

When passing a union type argument to a function, how do I type the receiving function's arguments?

Let's say I have a union type as follows:

type State = {
  value: number
  things: []
}

type Action =
  | {
      type: 'INCREMENT'
      data: number
    }
  | {
      type: 'DECREMENT'
      data: number
    }
  | {
      type: 'DO_THING'
      data: {
        id: string
        name: string
      }
    }

And a reducer function like so:

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case 'INCREMENT':
      return increment(state, action)
    case 'DECREMENT':
      return decrement(state, action)
    case 'DO_THING':
      return addItem(state, action)
    default:
      return state
  }
}

When typing my little action helper functions, I'm greeted with an error. Example:

function increment(state: State, action: action): State {
  return {
    ...state,
    number: action.data + 1 // this is the culprit
  }
}

Basically, because of the union type for which data is either number or the object defined, I'm getting an error like so:

Type 'number | { id: string; value: string }' is not assignable to type 'number'

I get why the error is here, because value is indeed strongly typed as just number . But… how do I solve this? How do I correctly type things to make it all play nice?

You can use the Extract utility to pull out the Increment action by its type.

function increment(state: State, action: Extract<Action, { type: 'INCREMENT' }>): State {
  return {
    ...state,
    value: action.data + 1,
  };
}

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