Reputation: 1365
Following redux guide to typescript I came up with the following code for my reducer. Typescript can't infer the right types on the switch case statement, though.
Reading this answer and its pointed typescript docs, I was able to make it work using string literals on the type variable on the interface. But I don't wanna use literals in there, since I am exporting my actions strings in a Actions variable, like in the code below.
What am I missing to be able to make it work like on the redux guide?
export const Action = {
action1:'ACTION1',
action2:'ACTION2'
}
interface actionType1 {
type: typeof Action.action1,
stringPayload:string
}
interface actionType2 {
type: typeof Action.action2,
objectPayload:{
str: string
}
}
type actionType = actionType1 | actionType2;
interface stateType {
str:string,
}
const defaultState = {
str:''
};
const reducer = ( state = defaultState, action:actionType) : stateType => {
switch(action.type){
case Action.action1:
return {
str:action.stringPayload //stringPayload appears as error
}
/*
[ts]
Property 'stringPayload' does not exist on type 'actionType'.
Property 'stringPayload' does not exist on type 'actionType2'.
*/
case Action.action2:
return action.objectPayload //objectPayload appears as error
/*
[ts]
Property 'objectPayload' does not exist on type 'actionType'.
Property 'objectPayload' does not exist on type 'actionType1'
*/
default:
return state
}
}
Upvotes: 0
Views: 3701
Reputation: 74500
It compiles with errors, because Action.action1
, Action.action2
in reducer resolve to string. If you hover over your Action
type, you can see how it's interpreted:
const Action: {
action1: string;
action2: string;
}
You could also test that by writing following code
type TestAction2Prop = typeof Action.action2 // type TestAction2Prop = string
To solve that, you have to tell TypeScript explicitely that no literal types of Action
should be widened (e.g. 'ACTION1' to string). You do that by const assertions:
export const Action = {
action1:'ACTION1',
action2:'ACTION2'
} as const
Upvotes: 1
Reputation: 2317
Try this:
export class Action {
static action1:'ACTION1';
static action2:'ACTION2';
}
interface actionType1 {
type: typeof Action.action1,
stringPayload:string
}
interface actionType2 {
type: typeof Action.action2,
objectPayload:{
str: string
}
}
type actionType = actionType1 | actionType2;
interface stateType {
str:string,
}
const defaultState = {
str:''
};
const reducer = ( state = defaultState, action:actionType) : stateType => {
switch(action.type){
case Action.action1:
return {
str:action.stringPayload //stringPayload appears as error
}
/*
[ts]
Property 'stringPayload' does not exist on type 'actionType'.
Property 'stringPayload' does not exist on type 'actionType2'.
*/
case Action.action2:
return action.objectPayload //objectPayload appears as error
/*
[ts]
Property 'objectPayload' does not exist on type 'actionType'.
Property 'objectPayload' does not exist on type 'actionType1'
*/
default:
return state
}
}
Upvotes: 0