首页 > 解决方案 > React w/Typescript: useReducer, Action Interface w/ Union Type

问题描述

所以我试图使用钩子创建一个减速器,该useReducer钩子使用一个名为 Action 的接口,该接口具有一个可以是 astring或 a的属性number

type Actions = 'update_foo' | 'update_bar';

interface Action {
    type: Actions;
    value?: number | string;
}

我还为初始状态和const设置默认状态定义了一个接口:

interface InitialState {
    foo: number;
    bar: string;
}

const defaultState: InitialState = {
    foo: 1,
    bar: 'bar'
}

然后是我的减速器功能:

const fooBarReducer: React.Reducer<InitialState, Action> = (state: InitialState, action: Action) => {
    switch(action.type) {
        case 'update_foo':
            return { ...state, foo: action.value };
        case 'update_bar':
            return { ...state, bar: action.value };
        default:
            return defaultState;
    }
}

我遇到的这个问题是 Typescript 似乎不喜欢联合类型 def 并引发以下错误:

Type '(state: InitialState, action: Action) => { foo: string | number | undefined; bar: string | number; }' is not assignable to type 'Reducer<InitialState, Action>'. 
Call signature return types '{ foo: string | number | undefined; bar: string | number; }' and 'InitialState' are incompatible. The types of 'foo' are incompatible between these types. 
Type 'string | number | undefined' is not assignable to type 'string | number'. 
Type 'undefined' is not assignable to type 'string | number'.

我之前使用过联合类型,但没有使用 ReactsuseReducer钩子。这可以通过在接口foo中单独使用属性来解决,但如果可能的话,我想使用联合类型。barAction

非常感激任何的帮助!!

标签: reactjstypescript

解决方案


问题似乎是您在字段级别使用类型联合。这意味着任何字段都可以是任何类型(例如:type可能是update_foo并且value可能"str"是无效的)。如果将Action interface其更新为动作的联合(而不是每个字段都是联合),则可以实现您正在寻找的类型安全。

现在,当typeis时update_foo,TypeScript 会知道value 必须number. TypeScript 什么时候typeupdate_bar知道value 必须string.

我还假设在这种update_bar情况下,那应该bar代替foo?

type Action =
  | { type: "update_foo"; value: number }
  | { type: "update_bar"; value: string };

interface InitialState {
  foo: number;
  bar: string;
}

const defaultState: InitialState = {
  foo: 1,
  bar: "bar"
};

const fooBarReducer: React.Reducer<InitialState, Action> = (
  state: InitialState,
  action: Action
) => {
  switch (action.type) {
    case "update_foo":
      return { ...state, foo: action.value };
    case "update_bar":
      return { ...state, bar: action.value };
    default:
      return defaultState;
  }
};

有关更多详细信息,您可能正在寻找的模式是受歧视的 unions


推荐阅读