PayloadAction 的打字稿类型

时间:2021-04-26 14:33:31

标签: reactjs typescript redux redux-toolkit

我像这样使用 createSlice

import { createSlice, PayloadAction } from '@reduxjs/toolkit';

const initialState = {} as Order;

const order = createSlice({
  name: 'order',
  initialState,
  reducers: {
    setOrder: (_state, { payload }: PayloadAction<Order | null>) => payload,
  },
});

我收到以下错误:

<块引用>
Type 'SalesOrder | null' is not assignable to type 'void | SalesOrder | WritableDraft<SalesOrder>'.
  Type 'null' is not assignable to type 'void | SalesOrder | WritableDraft<SalesOrder>'.ts(2322)

当我将鼠标悬停在函数上时,我得到以下类型:

function(_state: WritableDraft<SalesOrder>, { payload }: PayloadAction<SalesOrder | null>): SalesOrder | null

我该如何解决这个问题?我希望值是 Ordernull

2 个答案:

答案 0 :(得分:1)

我现在无法对此进行测试,但您的错误可能来自该行:

const initialState = {} as Order;

您基本上是在告诉打字稿,initialState 变量必须是一个订单(并通过传递一个空对象向编译器撒谎),然后在您的减速器中,您希望将其设为 Order 或 null,打字稿将告诉你它不能是 null 或 Order,它必须是一个订单。

你应该尝试:

const initialState: null |订单 = 空

告诉我这件事?

编辑:我在 redux toolkit docs 中找到了解决方案,但它并不直观!

第一步:

type OrderState = Order | null;

到目前为止一切顺利。我们已经定义了您的状态应该具有的类型。

现在,对于混乱的部分,当您实际创建初始状态常量时,打字稿会将其类型缩小到其值,无论您告诉它是什么类型。

所以当你写这个时:

const initialState: OrderState = null

Typescript 会理解“此常量的类型为 null”,因此您的创建切片函数会理解“状态的类型为 null”。

解决方法是将正确的类型转换为空值:

const initialState = null as OrderState

我知道两个 initialState 声明应该产生相同的类型推断,但它显然不能那样工作。

这样做,这里的这一行:

setOrder: (_state, { payload }: PayloadAction<OrderState>) => payload,

不会输出错误,因为你代码的每一部分都知道什么是什么类型。

顺便说一句,将一个空对象 litteral 分配给 initialState 变量并不是一个好主意,因为您的状态永远不会是 {} 类型。它要么是一个表示有某物的订单,要么是 null 表示没有订单。

我强烈建议阅读 redux toolkit docs 的“使用 typescript”部分,因为我认为这不会是您最后一个 typescript/redux 奇怪的错误。我有很多!

答案 1 :(得分:1)

我认为您实际上应该设置初始状态的值,而不是将空对象断言为 Order 类型。在这里,我只是添加了随机属性,因为您没有包含类型 Order(只需将其更改为实际值)。除此之外,我将 initialState 设置为 Ordernull 类型。

type InitialOrderState = { Order | null };

const initialState: InitialOrderState = {
    orderId: "",
    status: "",
};

const order = createSlice({
  name: 'order',
  initialState,
  reducers: {
    setOrder: (state, { payload }: PayloadAction<InitialOrderState>) => payload,
  },
});