如何在打字稿中正确使用 createAsyncThunk 函数?

How do I properly use createAsyncThunk function with typescript?

您可以找到完整的项目 here

我有以下代码:

    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)
            })
    }

但我想正确键入回调的操作参数,换句话说,摆脱 'any' 类型。我已经发现正确的方法是输入 createAsyncThunk,但直到现在,我都不知道该怎么做。

文件的其余代码如下:

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;



但是如果我从操作中删除 'any',就会发生这种情况:

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

根本不要输入操作类型。如果您什么都不做,它会根据您的 asyncThunk 的类型正确推断出来。


            .addCase(addTodoAsync.fulfilled, (state, action) => {

就像 state 自动是正确的类型一样,action 也是 - addTodoAsync 调度的已完成操作的类型。