Search code examples
typescriptredux

type 'any' is not assignable to type 'never'


I am using (I think) an "index access parameter" to write to an object in my reducer:

export type SettingsState = {
    brainRadiusEstimate: number,
    displayProgressIndicator: boolean,
    respiratoryFilterUpperBound: string,
    patientFeedback: PatientFeedbackType,
    connectionStatus: ConnectionStatus,
    brainSize: BrainSize,
    version: 'BETA 2',
}

export type ChangeParameterAction = {
    type: 'CHANGE_PARAMETER',
    parameter: ParameterName,
    value: any
}


export default function settingsReducer(state: SettingsState = defaultState, action: ChangeParameterAction): SettingsState {
  switch (action.type) {
    case 'CHANGE_PARAMETER':
      const newState: SettingsState = { ...state };
      newState[action.parameter] = action.value;
      return newState;
    default:
      return state;
  }
}

I'm getting an error on newState[action.parameter] = action.value that says "Type 'any' is not assignable to type 'never'".

I see here (under "Fixes to unsound writes to indexed access types") that this is indeed to be expected in TypeScript. It says the solution is "If you are convinced that you are not dealing with an error, you can use a type assertion instead."

I've tried adding

type ValueTypes = number | string | boolean | null | PatientFeedbackType | ConnectionStatus | BrainSize | 'BETA 2

and changing the line to

newState[action.parameter] = action.value as ValueTypes;

as well as

const value: ValueTypes = action.value
newState[action.parameter] = value;

but I get the same error, simply with a different type that's not assignable to never.

Is there a way to do this parameter access without simply using @ts-ignore?


Solution

  • You don't have an index signature on the type. But! It's okay, because there's another way to skin this cat: A computed property name:

    const newState: SettingsState = { ...state, [action.parameter]: action.value };
    

    Depending on the definition of ParameterName, that should correct the problem. For instance, if ParameterName is keyof SettingsState, it will.

    Live on the playground (using type ParameterName = keyof SettingsState;)