'Notifications' 类型的参数不可分配给 'Notifications[] | Record<EntityId, Notifications>' 类型的参数

Argument of type 'Notifications' is not assignable to parameter of type 'Notifications[] | Record<EntityId, Notifications>'

我在使用 Redux Toolkit 创建异步 Thunk 并将所述 Thunk 用作 extraReducer 时遇到了这个问题。

当我像这样指定 Return argumentThunk ArgumentThunkApiConfig 时,它会在 notificationsAdapter.upsertMany():[=24= 行的问题标题中抛出错误]

export const fetchNotifications = createAsyncThunk<
  Notifications,
  void,
  { state: RootState }
>("notifications/fetchNotifications", async (_, { getState }) => {
  const allNotifications = selectAllNotifications(getState());
  const [latestNotification] = allNotifications;
  const latestTimestamp = latestNotification ? latestNotification.date : "";
  const response = await client.get(
    `/fakeApi/notifications?since=${latestTimestamp}`
  );
  return response.notifications;
});

const notificationsSlice = createSlice({
  name: "notifications",
  initialState,
  reducers: {
    allNotificationsRead(state) {
      Object.values(state.entities).forEach((notification) => {
        notification && (notification.read = true);
      });
    },
  },
  extraReducers: (builder) => {
    builder.addCase(fetchNotifications.pending, (state) => {
      state.status = "loading";
    });
    builder.addCase(fetchNotifications.rejected, (state, action) => {
      state.status = "failed";
      state.error = action.error.message as Error;
    });
    builder.addCase(fetchNotifications.fulfilled, (state, action) => {
      state.status = "succeeded";
      Object.values(state.entities).forEach((notification) => {
        notification && (notification.isNew = !notification.read);
      });
      notificationsAdapter.upsertMany(state, action.payload);
    });
  },
});

但是当我从 createAsyncThunk 中删除类型并断言 getState()RootState(它来自使用 export type RootState = ReturnType<typeof store.getState> 的商店时,不再有错误所以我不确定我之前设置的值有什么问题。

export const fetchNotifications = createAsyncThunk(
  "notifications/fetchNotifications",
  async (_, { getState }) => {
    const allNotifications = selectAllNotifications(getState() as RootState);
    const [latestNotification] = allNotifications;
    const latestTimestamp = latestNotification ? latestNotification.date : "";
    const response = await client.get(
      `/fakeApi/notifications?since=${latestTimestamp}`
    );
    return response.notifications;
  }
);

可找到此代码 here

你必须非常小心 as 断言,因为如果你断言某些东西被证明是不正确的,你会产生问题。例如,您的类型 Errorstring | nullaction.error.messagestring | undefined。当它是 undefined 时会发生什么?

而不是坚持 Typescript 你有正确的类型:

state.error = action.error.message as Error;

您实际上应该通过使用无效合并将 undefined 替换为 null:

来强制您拥有正确的类型
state.error = action.error.message ?? null;

@Nadia 的评论是正确的。 upsertMany 需要数组 Notifications[] 或键控对象 Record<EntityId, Notifications>。您的 fetchNotifications 操作是 return 发送一条通知 Notifications。您的 client.get 响应是 any,因此您不会因 return 输入错误的类型而收到任何错误。

删除类型时不会出现任何错误,因为现在您的 fetchNotifications 操作 returns any.

您想确保您正在 return 数组 Notifications[]


在我看来,避免此类错误的最佳方法是使用强类型 client,它可以 return 基于端点的正确类型。

interface EndpointMap {
  "/fakeApi/notifications": Notifications;
}

interface Client {
  getOne<K extends keyof EndpointMap>(
    endpoint: K,
    id: string
  ): Promise<EndpointMap[K]>;

  getMany<K extends keyof EndpointMap>(
    endpoint: K,
    args: Record<string, any>
  ): Promise<EndpointMap[K][]>;
}