将Server Action作为Props传入Client Component的TS警告问题
解决将Server Action作为Props传入Client Component时的TS71007警告
问题场景
将Server Action作为props传入Client Component时,触发TypeScript警告:
TS71007: Props must be serializable for components in the "use client" entry file, "clientStatusFormAction" is invalid.
相关代码如下:
Server Component代码
export default async function EditClientStatus({params}: { params: { id: number } }) { const clientStatus = await getClientStatusById(params.id); const editClientStatusAction = async (_prevState: any, formData: FormData): Promise<ApiResponse<ClientStatus>> => { 'use server'; // 业务逻辑 } return ( <div> <h1>Edit Client Status</h1> <ClientStatusForm clientStatus={clientStatus.result} clientStatusFormAction={editClientStatusAction} /> </div> ); }
Client Component代码
"use client"; // 省略导入 type ClientStatusFormProps = { clientStatus: ClientStatus, clientStatusFormAction: (_prevState: any, formData: FormData) => Promise<ApiResponse<ClientStatus>> }; export default function ClientStatusForm({clientStatus, clientStatusFormAction}: ClientStatusFormProps) { const [formState, formAction] = useFormState<Promise<ApiResponse<ClientStatus>>, FormData>(clientStatusFormAction, {success: false, error: {errorType: "", messages: []} }); return ( <form action={formAction}> <div className="flex flex-wrap mb-6"> <GenericInput name="statusName" type="text" label="Status Name" required={true} isTwoColumn={true} maxLength={124} defaultValue={clientStatus.statusName} /> <GenericInput name="description" type="text" label="Status Description" required={true} isTwoColumn={true} maxLength={255} defaultValue={clientStatus.description} /> </div> <SubmitButton buttonText="Save" /> </form> ); }
原因分析
Next.js要求Client Component的props必须是可序列化类型(如字符串、数字、普通对象等)。直接在Server Component内部定义的editClientStatusAction函数,TypeScript无法识别它是Next.js专属的Server Action,会将其判定为普通函数——而函数不属于可序列化范畴,因此抛出警告。
解决方案
方案1:将Server Action独立导出(推荐)
把Server Action从Server Component内部抽离,作为单独的导出函数。Next.js会自动标记这类带'use server'的独立导出函数为Server Action,TypeScript也能正确识别其类型,彻底消除警告。
修改后的Server Component代码:
// 独立导出Server Action export async function editClientStatusAction(_prevState: any, formData: FormData): Promise<ApiResponse<ClientStatus>> { 'use server'; // 业务逻辑 } export default async function EditClientStatus({params}: { params: { id: number } }) { const clientStatus = await getClientStatusById(params.id); return ( <div> <h1>Edit Client Status</h1> <ClientStatusForm clientStatus={clientStatus.result} clientStatusFormAction={editClientStatusAction} /> </div> ); }
同时更新Client Component的props类型,使用Next.js提供的Action类型标注Server Action:
"use client"; import type { Action } from 'next/app'; // 省略其他导入 type ClientStatusFormProps = { clientStatus: ClientStatus, clientStatusFormAction: Action<Promise<ApiResponse<ClientStatus>>, FormData> }; // 组件逻辑不变
方案2:类型断言(快速临时解决)
如果不想调整代码结构,可以通过类型断言强制告诉TypeScript该函数是合法的props:
在Server Component传递props时添加断言:
<ClientStatusForm clientStatus={clientStatus.result} clientStatusFormAction={editClientStatusAction as unknown as Action<Promise<ApiResponse<ClientStatus>>, FormData>} />
或者直接修改Client Component的props类型为any(不推荐,会丢失类型检查能力):
type ClientStatusFormProps = { clientStatus: ClientStatus, clientStatusFormAction: any };
说明
方案1符合Next.js的设计规范,能保留完整的类型检查;方案2适合快速临时消除警告,但会牺牲部分类型安全性。
内容的提问来源于stack exchange,提问作者cela
相关产品推荐
相关产品推荐

