Reputation: 145
i'm new with TypeScript. I'm trying to use TypeScript with Redux but i'm blocked with this error: Property 'user' does not exist on type 'WritableDraft<{ name: string; }>'.
I was going step by step with tutorial on Youtube but it's not working on my project. Any ideas?
Here's my code:
import { createSlice } from '@reduxjs/toolkit';
import React from 'react';
export const userSlice = createSlice({
name: 'user',
initialState: {
name: '',
},
reducers: {
login: (state, action) => {
state = action.payload;
},
logout: (state) => {
state.user = null;
},
},
});
export const { login, logout } = userSlice.actions;
export const selectUser = (state: { user: { user: any } }) => state.user.user;
export default userSlice.reducer;
Upvotes: 6
Views: 15484
Reputation: 65
Redux will infer the type of state
(in your reducers) from the initialState
value passed to the createSlice
function, here:
...
initialState: {
name: '',
}, // type of your state is: { name: string } - notice how it does not have a `user` property!
...
In your reducers, you will get a WritableDraft
instance of the state as the first argument, like so:
logout: (state: WritableDraft<{ name: string }>) => {
state.user = null; // 'user' property does not exist in your state type! (as defined in the `initialState`)
},
To accomplish what I think you're trying to accomplish, all you have to do is abstract the name
variable inside of a user
property, like so:
...
initialState: {
user: { name: '' }
},
reducers: {
login: (state, action) => {
state.user = action.payload;
},
logout: (state) => {
state.user = null;
},
}
...
At this point I would recommend explicitly typing your state and action payloads.
E.g.:
export type User {
name: string
}
export type UserState = {
user: User | null
}
... and in your reducers:
login: (state, action: PayloadAction<User>) => {
state.user = action.payload; // action.payload will be of type 'User'
},
logout: (state) => {
state.user = null
}
Anyway, it seems you missed something from the tutorial since in your own code you have a selector defining your state as state: { user: { user: any } }
. Explicitly defining your state type, like above, should help mitigate these issues in the future.
Upvotes: 2
Reputation: 1656
If you've cross checked your code and its fine.
Change the version of redux-toolkit to a previous one, in my case, I used 1.8.0
and everything started working again.
Or delete node_modules and run npm install
or yarn
Upvotes: 0
Reputation: 102327
The data shape of the user
state slice is { name: string }
.
import { combineReducers, configureStore, createSlice } from '@reduxjs/toolkit';
export const userSlice = createSlice({
name: 'user',
initialState: {
name: '',
},
reducers: {
login: (state, action) => {
state.name = action.payload;
},
logout: (state) => {
state.name = '';
},
},
});
export const { login, logout } = userSlice.actions;
export const selectUser = (state: { user: { name: string } }) => state.user;
const store = configureStore({ reducer: combineReducers({ user: userSlice.reducer }) });
console.log(store.getState());
store.subscribe(() => {
console.log('selectUser:', selectUser(store.getState()));
});
console.log(store.dispatch(login('John')));
Logs:
{ user: { name: '' } }
selectUser: { name: 'John' }
{ type: 'user/login', payload: 'John' }
Upvotes: 0