Reputation: 2920
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?
Upvotes: 1
Views: 64
Reputation: 1421
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.
Upvotes: 1
Reputation: 25310
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.
Upvotes: 2