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

Next.js 15动态API路由TypeScript类型错误:params需为Promise?

Next.js 15动态API路由的TypeScript类型错误排查

问题背景

我在使用Next.js v15.3.3开发动态API路由时遇到TypeScript类型错误,环境版本如下:

  • TypeScript ^5
  • React ^19.0.0

编译错误信息

Type error: Type '{ __tag__: "PATCH"; __param_position__: "second"; __param_type__: { params: { id: string; }; }; }' does not satisfy the constraint 'ParamCheck<RouteContext>'.
  The types of '__param_type__.params' are incompatible between these types.
    Type '{ id: string; }' is missing the following properties from type 'Promise<any>': then, catch, finally, [Symbol.toStringTag]

  281 |     Diff<
  282 |       ParamCheck<RouteContext>,
> 283 |       {
      |       ^
  284 |         __tag__: 'PATCH'
  285 |         __param_position__: 'second'
  286 |         __param_type__: SecondArg<MaybeField<TEntry, 'PATCH'>>

从错误信息来看,Next.js内部期望params的类型为Promise<{ id: string }>而非普通的{ id: string }。

引发错误的处理器代码

import { NextRequest, NextResponse } from "next/server";
import { connectDB } from "@/app/lib/db";
import AnswerHistory from "@/app/models/AnswerHistory";
import { ObjectId } from "mongodb";
import { AnswerHistoryUpdatableFields } from "@/types/answerHistory";

export async function PATCH(
  req: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    await connectDB();

    const id = (await params).id;

    if (!id) {
      return NextResponse.json({ error: "缺少ID参数" }, { status: 400 });
    }

    const updateData: Partial<AnswerHistoryUpdatableFields> = await req.json();

    if (!updateData.answer || typeof updateData.answer !== "string") {
      return NextResponse.json(
        { error: "{answer}不能为空且必须为字符串类型" },
        { status: 400 }
      );
    }

    if (
      updateData.score &&
      (typeof updateData.score !== "number" ||
        updateData.score < 0 ||
        updateData.score > 10)
    ) {
      return NextResponse.json(
        { error: "{score}必须为0-10之间的数字" },
        { status: 400 }
      );
    }

    updateData.updatedAt = new Date();

    const updatedRecord = await AnswerHistory.findByIdAndUpdate(
      new ObjectId(id),
      updateData,
      { new: true }
    ).lean();

    if (!updatedRecord) {
      return NextResponse.json(
        { error: "记录不存在" },
        { status: 404 }
      );
    }

    return NextResponse.json(updatedRecord);
  } catch (err) {
    console.error("❌ 更新失败:", err);
    return NextResponse.json(
      {
        error: "服务器内部错误",
        details: err instanceof Error ? err.message : String(err),
      },
      { status: 500 }
    );
  }
}

若将params声明为普通对象{ id: string },构建时会触发上述错误。

疑问

  • 这是Next.js 15的预期行为吗?
  • 为何生成的类型会将params视为Promise?
  • 使用Promise<{ id: string }>作为临时解决方案是否正确?有没有更优方案?

解答

  1. 是否为Next.js 15的预期行为?
    不是。Next.js 13+的App Router中,API路由的params参数本身是同步的普通对象({ params: { id: string } }),并非Promise类型。出现这种类型错误大概率是版本兼容问题或类型定义异常。

  2. 为何类型将params视为Promise?
    可能的原因有两种:

  • Next.js v15.3.3本身存在类型定义bug,错误地将params标记为Promise类型;
  • 项目中存在依赖版本冲突,比如@types/next或相关类型包版本不匹配,导致类型推断异常。
  1. 临时方案是否正确?更优方案是什么?
    用Promise<{ id: string }>作为临时方案可以绕过编译错误,但不符合Next.js的设计规范,属于权宜之计。更优方案如下:
  • 降级Next.js版本:如果v15.3.3存在已知类型bug,可以降级到v15.3.2或更稳定的版本;
  • 检查依赖冲突:运行npm ls @types/next或yarn list @types/next查看是否存在多版本类型包,清理重复依赖后重新安装;
  • 显式导入正确类型:使用Next.js提供的RouteContext类型来定义参数,示例代码:
    import type { RouteContext } from "next/server";
    
    export async function PATCH(
      req: NextRequest,
      context: RouteContext<{ id: string }>
    ) {
      const { id } = context.params;
      // ...后续逻辑
    }
    
  • 更新TypeScript版本:确保TypeScript版本与Next.js 15兼容(建议使用TypeScript 5.3+),避免因TS版本过低导致的类型推断问题。

内容的提问来源于stack exchange,提问作者Yellow Clock

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 16:45:59