I've recently updated "react-redux": "8.0.4" to "8.0.5" and "@reduxjs/toolkit" from "1.8.6" to "2.0.0". In doing so I've noticed a change in the type definition of EntitySelectors
in Redux Toolkit's EntityAdapter
, particularly for the selectById
selector.
Previously, the type explicitly allowed for undefined
as a possible return type. However, the updated definition uses Compute<UncheckedIndexedAccess<T>>
, which seems to complicate type inference.
This is the old definition:
export interface EntitySelectors<T, V> {
selectIds: (state: V) => EntityId[];
selectEntities: (state: V) => Record<EntityId, T>;
selectAll: (state: V) => T[];
selectTotal: (state: V) => number;
selectById: (state: V, id: EntityId) => T | undefined;
}
And this is the new definition:
export interface EntitySelectors<T, V, Id extends EntityId> {
selectIds: (state: V) => Id[];
selectEntities: (state: V) => Record<Id, T>;
selectAll: (state: V) => T[];
selectTotal: (state: V) => number;
selectById: (state: V, id: Id) => Compute<UncheckedIndexedAccess<T>>;
}
Previously I would define my entity selectors like so:
/* Export selectors ------------------------------------- */
export const selectUsers = usersAdapter.getSelectors(
(state: RootState) => state.users
);
And then call them like so:
const user = useAppSelector((state) =>
selectUsers.selectById(state, userId ?? "")
);
user
would then be inferred as User_Entity
or undefined
However since updating user
is now only inferred as User_Entity
which then doesn't cover the posibilty of undefined values, say for example if the userId is incorrect and doesn't exist as an id in the users slice.
I've got around this by doing the following:
export const { selectById, ...rest } = usersAdapter.getSelectors(
(state: RootState) => state.users,
);
export const selectUsers = {
...rest,
selectById: (state: RootState, userId: EntityId): User_Entity | undefined =>
selectById(state, userId),
};
However I'm curious if there are better ways to approach this, especially in light of the new type definitions. Any insights or suggestions would be greatly appreciated!
As noted in the migration guide, the entity typing now depends on your noUncheckedIndexedAccess
setting - if it's on, it'll be possibly undefined, if not it won't.
As you've noted, you can manually annotate to add the possibly undefined type in a case by case basis.