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
asserthelper (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: