简体   繁体   中英

TypeScript and Union Types

Given: Reducer accepts one of the four actions:

interface ItemAction {
    type: 'ADD_TODO'|'DELETE_TODO'|'TOGGLE_TODO',
    id: number
}

interface QueryAction {
    type: 'SET_QUERY',
    query: string
}

I expect the code of the reducer contain something like:

if (action as ItemAction) {
   console.log(action.id); // typescript knows that "id" is available here
} else {
   console.log(action.query); // typescript knows that action is of type QueryAction and hence "query" is available here
}

How do I achieve that with TypeScript?

The easiest solution is to use the in operator :

let action: ItemAction | QueryAction = ...;
if ('id' in action) {
  // Type inferred as ItemAction
} else {
  // Type inferred as QueryAction
}

For more complex cases, you can use type guards .

This can be handled with a user-defined typeguard. For example

function isItemAction(someAction: any): someAction is ItemAction {
  if(someAction.id !== undefined and typeof someAction.id === 'number') {
    return true
  } else return false
}

if (if isItemAction(action)) {
  console.log(action.id); // typescript knows that "id" is available here
} 

A few things to know about typeguards: (1) they require the use of the type predicate "is" language; (2) they are conventionally named as I have named them, isX; (3) TS has no way of knowing that the evaluation logic in your function is accurate, that's up to you, in other words, a typeguard that always evaluates to true will be fine from TS's perspective.

See here for more info on writing user defined type guards.

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