You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 17:23:18