0

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 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Exactly what I needed. Thanks. So what I'm understanding is discrimination type is used to narrow down the types in a union by using a single type property as a literal type. And thus I think in my case the as the type is common but since it is a string, and both types can be possible.
Yes. In discriminated types you must have one property, having literal type based on which you can differentiate. typing it as string does not provide that much of type safety and auto complete assistance as literal types does.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.