help with typization in React/Redux and null handling #4776
-
I use React with Redux and TypeScript export interface UserState {
user: User | null;
}
const initialState: UserState = {
user: null,
};
const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
setUser: (state, action: PayloadAction<User>) => {
state.user = action.payload;
},
},
});
export const { setUser } = userSlice.actions;
export const selectUser = (state: { user: UserState }): User => state.user.user; // <------ possible null here
export const selectUserId = (state: { user: UserState }): string => state.user.user.id; // <------ possible null here
export default userSlice.reducer; The issue that I have is that initially, the user is unknown, but it is known after the user is authenticated,so in 99% of places and I don't want to handle the possible user being null in all components. The protected route should redirect to the login page in this case, but I still have an issue where the user type could be null. Could you please help me organize this better? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
it's probably not the recommended approach, but I like to use an function assert(condition: unknown, message: string): asserts condition {
if (!condition) throw new Error(message)
}
const selectNullableUser = (state: RootState) => state.user.user;
const selectUser = (state: RootState) => {
const user = selectNullableUser(state);
assert(user, "Only call selectUser if you know user is defined!");
return user; // now narrowed
}
const selectUserId = (state: RootState) => selectUser(state).id |
Beta Was this translation helpful? Give feedback.
-
before react render, get default state for user and put in store you have const setUserHandler = () => {
try {
const userToken = JSON.parse(localStorage.getItem("user"));
if (!userToken) return;
store.dispatch(authAction.setUser(jwtDecodeHandler(userToken)));
} catch (e) {
console.error("User Setting Exception : ", e)
}
};
setUserHandler()
ReactDOM.createRoot(document.getElementById('root')).render(
<StrictMode>
<Provider store={store}>
<App/>
</Provider>
</StrictMode>,
) |
Beta Was this translation helpful? Give feedback.
it's probably not the recommended approach, but I like to use an
assert
helper (also known asinvariant
) inside selectors for things that should never happen but still need to be proved to typescript. that way if the thing that should never happen happens, i get an intuitive error message rather than "tried to read property of undefined" or whatever. for example: