Jimmy
Jimmy

Reputation: 3850

Type-checking a TypeScript reducer receiving action types

I am trying to create a TypeScript redux reducer that accepts an actionType as a key value, however I am struggling to define the proper interface for my state. When doing so, I am getting the following message:

TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'SampleState'. No index signature with a parameter of type 'string' was found on type 'SampleState'.

enter image description here

How do I properly type check my reducer for when it receives an actionType? Thanks, you can see the sample code below.

sampleActionTypes.ts:

export const FOO = 'FOO';
export const BAR = 'BAR';
export const TURN_ON = 'TURN_ON';
export const TURN_OFF = 'TURN_OFF';

interface TurnOn {
  type: typeof TURN_ON;
  actionType: string;
}

interface TurnOff {
  type: typeof TURN_OFF;
  actionType: string;
}

export type Types = TurnOn | TurnOff;

sampleReducer.ts:

import { BAR, FOO, TURN_OFF, TURN_ON, Types } from './sampleActionTypes';

export interface SampleState {
  [FOO]: {
    toggle: boolean;
  };
  [BAR]: {
    toggle: boolean;
  };
}

const initialState: SampleState = {
  [FOO]: {
    toggle: false,
  },
  [BAR]: {
    toggle: false,
  },
};

const sampleReducer = (state = initialState, action: Types): SampleState => {
  switch (action.type) {
    case TURN_ON:
      return {
        ...state,
        [action.actionType]: {
          ...state[action.actionType],
          toggle: true,
        },
      };
    case TURN_OFF:
      return {
        ...state,
        [action.actionType]: {
          ...state[action.actionType],
          toggle: false,
        },
      };
    default:
      return state;
  }
};

export default sampleReducer;

Upvotes: 0

Views: 763

Answers (2)

Jimmy
Jimmy

Reputation: 3850

Updating the SampleState interface to the following solved this issue:

export interface SampleState {
  [key: string]: {
    toggle: boolean;
  };
}

Upvotes: 0

Richard Haddad
Richard Haddad

Reputation: 1004

Your state has as keys FOO | BAR following your SampleState interface. And your Types['actionType'] is string.

So when you're doing state[action.actionType], you're doing SampleState[string]. But SampleState accepts only FOO or BAR !

A solution, according to your needs, may be to type Types['actionType']: (typeof FOO) | (typeof BAR) (something like that).

Also carefull to how you're naming your fields. Maybe it's just for the example, but actionType when there is already a type in an action interface seems redondant and quite confusing.

Upvotes: 1

Related Questions