I've recently decided to refactor an existing redux project to redux-toolkit. The project also uses typescript. In authSlice.ts
I have created async thunk and added handler for 'fullfilled' case to extraReducers
. And now typescript gives me a warning
Property 'idToken' does not exist on type 'PayloadAction<{ idToken: string; email: string; refreshToken: string; expiresIn: string; localId: string; registered: boolean; }, string, { arg: ReqPayload; requestId: string; requestStatus: "fulfilled"; }, never>'.ts(2339)
I'm quite novice to typescript, have no enough knowledge to spot an issue. Please help me to work it out.
import axios from 'axios'
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
interface ReqPayload {
email: string,
password: string,
returnSecureToken: boolean
}
interface ResPayload {
data: {
idToken: string,
email: string,
refreshToken: string,
expiresIn: string,
localId: string,
registered: boolean
}
}
export const authenticate = createAsyncThunk(
'auth',
async ({ email, password, returnSecureToken }: ReqPayload) => {
const API_KEY = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
const payload: ReqPayload = { email, password, returnSecureToken: true }
const response: ResPayload = await axios.post(
`https://identitytoolkit.googleapis.com/v1/accounts:${returnSecureToken ? 'signInWithPassword' : 'signUp'}?key=${API_KEY}`,
payload
)
const { localId, idToken, expiresIn } = response.data
const expirationDate = new Date(new Date().getTime() + (+expiresIn * 1000))
localStorage.setItem('idToken', idToken)
localStorage.setItem('localId', localId)
localStorage.setItem('expirationDate', '' + expirationDate)
return response.data
}
);
interface AuthState {
idToken: string | null,
localId: string | null,
error: object | null,
isLoading: boolean,
}
const initialState: AuthState = {
idToken: null,
localId: null,
error: null,
isLoading: false,
}
export const authSlice = createSlice({
name: 'auth',
initialState,
// The `reducers` field lets us define reducers and generate associated actions
reducers: {
},
// The `extraReducers` field lets the slice handle actions defined elsewhere,
// including actions generated by createAsyncThunk or in other slices.
extraReducers: (builder) => {
builder
.addCase(authenticate.fulfilled, (state, action) => {
state.idToken = action.idToken
state.localId = action.localId
state.error = null
state.isLoading = false
})
},
});
You're trying to use action.idToken
in your reducer, but that won't exist. Redux Toolkit always generates action objects that keep their data in an action.payload
field. So, you need to use action.payload.idToken
instead.
TypeScript should actually be giving you autocompletion in your IDE and will show you that action.payload
exists, and from there that action.payload.idToken
exists.