You can find the complete project here.
I have the following code:
extraReducers: (builder) => {
builder
.addCase(getTodosAsync.fulfilled, (state, action:any) => {
return action.payload.todos
})
.addCase(addTodoAsync.fulfilled, (state, action:any) => {
state.push(action.payload.todo)
})
.addCase(toggleCompleteAsync.fulfilled, (state, action:any) => {
const index = state.findIndex(
(todo) => todo.id === action.payload.todo.id
)
state[index].completed = action.payload.todo.completed
})
.addCase(deleteTodoAsync.fulfilled, (state, action:any) => {
return state.filter((todo) => todo.id !== action.payload.id)
})
}
but I want to properly type the action parameter of the callbacks,in other words, get rid of the 'any' type. I already found out that the correct way is typing the createAsyncThunk, but until now, I don't know how to do it.
The rest of the file's code is as the following:
import {
createAsyncThunk,
createSlice,
PayloadAction
} from '@reduxjs/toolkit';
// import {AsyncThunkFulfilledActionCreator} from '../../node_modules/@reduxjs/toolkit/src/createAsyncThunk'
import { nanoid } from 'nanoid';
interface propsPayload {
title?: string,
id?: string,
completed?: boolean
}
const initialState = [
{}
] as Array<propsPayload>
export const getTodosAsync = createAsyncThunk(
'todos/getTodosAsync',
async () => {
const resp = await fetch('http://localhost:7000/todos');
if (resp.ok) {
const todos = (await resp.json()) ;
return { todos } ;
}
}
);
export const addTodoAsync = createAsyncThunk(
'todos/addTodoAsync',
async (payload: propsPayload) => {
const resp = await fetch('http://localhost:7000/todos', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ title: payload.title }),
});
if (resp.ok) {
const todo = await resp.json();
return { todo } ;
}
}
);
export const toggleCompleteAsync = createAsyncThunk(
'todos/completeTodoAsync',
async (payload: propsPayload) => {
const resp = await fetch(`http://localhost:7000/todos/${payload.id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ completed: payload.completed }),
});
if (resp.ok) {
const todo = await resp.json();
return { todo } ;
}
}
);
export const deleteTodoAsync = createAsyncThunk(
'todos/deleteTodoAsync',
async (payload: propsPayload) => {
const resp = await fetch(`http://localhost:7000/todos/${payload.id}`, {
method: 'DELETE',
});
if (resp.ok) {
return { id: payload.id };
}
}
);
export const todoSlice = createSlice({
name: 'todos',
initialState: initialState,
reducers: {
addTodo: (state: Array<propsPayload>, action: PayloadAction<propsPayload>) => {
const todo = {
id: nanoid(),
title: action.payload.title,
completed: false,
};
state.push(todo);
},
toggleComplete: (state: Array<propsPayload>, action: PayloadAction<propsPayload>) => {
const index = state.findIndex((todo) => todo.id === action.payload.id);
state[index].completed = action.payload.completed;
},
deleteTodo: (state: Array<propsPayload>, action: PayloadAction<propsPayload>) => {
return state.filter((todo) => todo.id !== action.payload.id);
},
},
extraReducers: (builder) => {
builder
.addCase(getTodosAsync.fulfilled, (state, action:any) => {
return action.payload.todos
})
.addCase(addTodoAsync.fulfilled, (state, action:any) => {
state.push(action.payload.todo)
})
.addCase(toggleCompleteAsync.fulfilled, (state, action:any) => {
const index = state.findIndex(
(todo) => todo.id === action.payload.todo.id
)
state[index].completed = action.payload.todo.completed
})
.addCase(deleteTodoAsync.fulfilled, (state, action:any) => {
return state.filter((todo) => todo.id !== action.payload.id)
})
}
});
export const { addTodo, toggleComplete, deleteTodo } = todoSlice.actions;
export default todoSlice.reducer;
CodePudding user response:
Do not type the action type at all. It is inferred correctly from the type of your asyncThunk if you do nothing at all.
.addCase(addTodoAsync.fulfilled, (state, action) => {
Just like state
is automatically the right type, action
is too - the type of a fulfulled action dispatched by addTodoAsync
.
CodePudding user response:
But if I remove the 'any' from action, this occurred:
Object is possibly 'undefined'.ts(2532)
(parameter) action: PayloadAction<{
todos: any;
} | undefined, string, {
arg: void;
requestId: string;
requestStatus: "fulfilled";
}, never>
Object is possibly 'undefined'.ts(2532)
(property) payload: {
todos: any;
} | undefined