'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 argument
、Thunk Argument
和 ThunkApiConfig
时,它会在 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
断言,因为如果你断言某些东西被证明是不正确的,你会产生问题。例如,您的类型 Error
是 string | null
但 action.error.message
是 string | 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][]>;
}
我在使用 Redux Toolkit 创建异步 Thunk 并将所述 Thunk 用作 extraReducer 时遇到了这个问题。
当我像这样指定 Return argument
、Thunk Argument
和 ThunkApiConfig
时,它会在 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
断言,因为如果你断言某些东西被证明是不正确的,你会产生问题。例如,您的类型 Error
是 string | null
但 action.error.message
是 string | 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][]>;
}