代码之家  ›  专栏  ›  技术社区  ›  yudhiesh

“Notifications”类型的参数不能分配给“Notifications[]| Record<EntityId,Notifications>”类型的变量

  •  0
  • yudhiesh  · 技术社区  · 5 年前

    在使用Redux Toolkit创建Async Thunk并将其用作extraReducer时,我遇到了这个问题。

    当我指定 Return argument , Thunk Argument 以及 ThunkApiConfig 就像这样,它会在第行抛出问题标题中的错误 notificationsAdapter.upsertMany() :

    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 .

    0 回复  |  直到 5 年前
        1
  •  1
  •   Linda Paiste    5 年前

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

    与其坚持用打字机输入正确的类型:

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

    实际上,您应该通过使用nullish合并来替换来强制您拥有正确的类型 未定义 具有 null :

    state.error = action.error.message ?? null;
    

    @Nadia的评论是正确的。 upsertMany 需要一个数组 Notifications[] 或键控对象 Record<EntityId, Notifications> .你的 fetchNotifications 操作返回单个通知 Notifications .你的 client.get 响应是 any 因此,返回错误的类型不会导致任何错误。

    当你删除这些类型时,你不会得到任何错误,因为现在你的 fetch通知 动作返回 任何 .

    您要确保返回的是一个数组 通知[] .


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

    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][]>;
    }
    
    推荐文章