Using union types in conditional blocks in typescript

95 Views Asked by At

I am learning typescript and trying to strong-typed useReducer with reactjs. This is logic for reducer, but typescript is yelling at me that property incStep doesn't exist on Act because it doesn't exists on Decrement.

type Increment = {
    type: string,
    incStep: number
}

type Decrement = {
    type: string,
    decStep: number
}

type State = {
    count: number
}

type Actions = Increment | Decrement

const reducer = (state: State, action: Actions) : State =>  {

    if(action.type == 'Inc') {
        return {count: state.count + action.incStep }
    } else if(action.type == 'Dec') {
        return {count: state.count - action.decStep}
    }

    return state
}

Getting the following error: Property 'incStep' does not exist on type 'Act'. Property 'incStep' does not exist on type 'Dec'.

Now I think Union types mean All or either one.

for example

const action : Actions = {
  type: 'inc',
  incStep: 1,
  decStep: 2'
}

// or

const action : Actions = {
  type: 'inc',
  incStep: 1,
}

// or 

const action : Actions = {
  type: 'dec',
  decStep: 1,
}

Also I know that switch statement is good to use here, but I used if-else as the number of action types were only two.

I know if I use string literal type 'inc' | 'dec', then I have no problem.

Can someone please explain What am I doing wrong?

1

There are 1 best solutions below

2
Shubham Waje On

I think use of discrimination types is ideal here.

You can learn more about discrimination types here

type Increment = {
  type: "Inc"; // this field is the differentiator
  incStep: number;
};

type Decrement = {
  type: "Dec"; // this field is the differentiator
  decStep: number;
};

type State = {
  count: number;
};

type Actions = Increment | Decrement;

const reducer = (state: State, action: Actions): State => {
  switch (action.type) {
    case "Inc":
      return { count: state.count + action.incStep };
    case "Dec":
      return { count: state.count - action.decStep };
    default:
      return state;
  }
};

Using switch case is a better and concise way to write such code as it provides better readability and follows DRY principal.