Next.js表单action绑定Server Action触发TypeScript类型错误
解决Next.js中Form Action与Server Action类型不匹配问题
在Next.js项目里,客户端组件/components/button.tsx的DeleteButton组件中,将服务端组件/lib/actions.ts的deleteImage函数通过bind绑定id后赋值给form的action属性时,触发TypeScript类型错误。核心原因是deleteImage返回的Promise<{ message: string; } | undefined>与form action要求的void | Promise<void>类型不兼容。
相关客户端组件代码
export const DeleteButton = ({ id }: { id: string }) => { const deleteImageWithId = deleteImage.bind(null, id); return ( <form action={deleteImageWithId} className="py-3 text-sm bg-gray-50 rounded-br-md w-full hover:bg-gray-100 text-center" > <DeleteBtn /> </form> ); };
相关服务端组件代码
// Delete Image export const deleteImage = async (id: string) => { const data = await getImageById(id); if (!data) return { message: "No data found" }; await del(data.image); try { await prisma.upload.delete({ where: { id }, }); } catch (error) { return { message: "Failed to delete data" }; } revalidatePath("/"); };
完整错误信息
./components/button.tsx:44:7 Type error: Type '() => Promise<{ message: string; } | undefined>' is not assignable to type 'string | ((formData: FormData) => void | Promise<void>) | undefined'. Type '() => Promise<{ message: string; } | undefined>' is not assignable to type '(formData: FormData) => void | Promise<void>'. Type 'Promise<{ message: string; } | undefined>' is not assignable to type 'void | Promise<void>'. Type 'Promise<{ message: string; } | undefined>' is not assignable to type 'void | Promise<void>'. Type 'Promise<{ message: string; } | undefined>' is not assignable to type 'Promise<void>'. Type '{ message: string; } | undefined' is not assignable to type 'void'. Type '{ message: string; }' is not assignable to type 'void'.
解决方案
方案1:修改Server Action的返回逻辑,适配类型要求
Next.js的Form Action不期望函数返回自定义对象,而是推荐通过抛出错误或结合useFormState处理错误信息。调整deleteImage函数:
// Delete Image export const deleteImage = async (id: string) => { const data = await getImageById(id); if (!data) { throw new Error("No data found"); } await del(data.image); try { await prisma.upload.delete({ where: { id }, }); } catch (error) { throw new Error("Failed to delete data"); } revalidatePath("/"); };
之后前端可以用useFormState捕获错误并展示,同时函数返回Promise<void>(抛出错误时会被捕获,不影响类型),完全符合Form Action的要求。
方案2:在客户端包装适配类型的函数
如果不想修改原有Server Action,可以在客户端组件中包装一个忽略返回值的函数:
export const DeleteButton = ({ id }: { id: string }) => { // 包装函数,适配Form Action的类型签名 const handleDelete = async (_formData: FormData) => { await deleteImage(id); }; return ( <form action={handleDelete} className="py-3 text-sm bg-gray-50 rounded-br-md w-full hover:bg-gray-100 text-center" > <DeleteBtn /> </form> ); };
这里handleDelete明确接受FormData参数(即使不用),并返回Promise<void>,完美匹配Form Action的类型要求,同时保留原有业务逻辑。
内容的提问来源于stack exchange,提问作者eko pram
相关产品推荐
相关产品推荐

