你如何在 redux 工具包 createSlice 中定义初始状态类型(并且类型不同)

How do you define the initial state type in redux toolkit createSlice (And the types are different)

这里有详细的记录:

Defining the Initial State Type

然而,当初始状态类型可能是多种不同类型时,问题就出现了。

import { createSlice } from "@reduxjs/toolkit";

// Type definitions
export const UNINITIALIZED = "UNINITIALIZED";
interface ICurrentCustomer {
  id: string;
  name: string;
}
interface ISetCurrentCustomerAction {
  type: string;
  payload: ICurrentCustomer;
}

// Initial state (This is intentional, null has special meaning here in my use case)
// This is the important part right here!!!!!!!!!!!!!!!!!!!!!!!
const initialState: ICurrentCustomer | typeof UNINITIALIZED | null = UNINITIALIZED;

const currentCustomerSlice = createSlice({
  name: "currentCustomer",
  initialState,
  reducers: {
    // I put any on state type here coz it will error
    setCurrentCustomer: (state: any, action: ISetCurrentCustomerAction) => {
      const { id, name } = action.payload;

      state.id = id;
      state.name = name;

      return state;
    },
  },
});

export const { setCurrentCustomer } = currentCustomerSlice.actions;

export default currentCustomerSlice.reducer;

这里的问题是 redux 工具包会将商店中的状态类型设置为字符串。因为很明显 UNINITIALIZED 是一个字符串。这将产生错误,控制台消息为:

TypeError: Cannot create property 'id' on string 'UNINITIALIZED'

这里是关于类型推断的:

How to describe the shape of the state in createSlice

我怎样才能使上面的代码工作? 感谢任何帮助。

提前致谢。

您可以使用带有 as 的类型转换来让 createSlice 正确推断类型,如下所示:

import { createSlice } from "@reduxjs/toolkit";

// Type definitions
export const UNINITIALIZED = "UNINITIALIZED";
interface ICurrentCustomer {
  id: string;
  name: string;
}
interface ISetCurrentCustomerAction {
  type: string;
  payload: ICurrentCustomer;
}

// Define a type for your state
type State = ICurrentCustomer | typeof UNINITIALIZED | null;

// Define your initial state
const initialState: State  = UNINITIALIZED;

const currentCustomerSlice = createSlice({
  name: "currentCustomer",
  // Do a type cast here, this will allow `createSlice` to infer the correct type
  initialState: initialState as State,
  reducers: {
    // You can use State type here now
    setCurrentCustomer: (state: State, action: ISetCurrentCustomerAction) => {
      const { id, name } = action.payload;

      // You will still need to check if state in `null` and `UNINITIALIZED` before accessing it
      if(state!== null && state !== UNINITIALIZED) {
        state.id = id;
        state.name = name;
      }

      // Or do something like this if you want to disregard previous state
      //state = {id, name};

      return state;
    },
  },
});

export const { setCurrentCustomer } = currentCustomerSlice.actions;

export default currentCustomerSlice.reducer;