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

Next.js构建时传递数据库Diary对象的TypeScript类型错误解决

解决Next.js中传递Diary对象到组件的TypeScript类型错误

问题核心

错误根源在于Prisma查询结果的类型不匹配:db.diary.findFirst()返回的类型是Diary | null,但DiaryEditForm组件的props要求传入必填的Diary类型,同时未处理数据库查询不到对应日记的场景,直接传递可能为null的值会引发类型报错及潜在运行时错误。

代码问题定位

页面代码(问题点)

import { db } from "@/db";
import DiaryEditForm from "@/components/diary-edit-form";
interface DiaryEditPageProps {
    params: {
        id: string;
    };
}
export default async function DiaryEditPage(props: DiaryEditPageProps) {
        const id = parseInt(props.params.id);
        const diary = await db.diary.findFirst({
            where: { id },
            });
        // 此处diary可能为null,不符合组件的必填Diary类型要求
        return (
        <div>
        <DiaryEditForm diary={diary} />
        </div>
    );
}

组件代码(依赖正确类型)

"use client";

import { Diary } from "@prisma/client";
import { useState } from "react";
import * as actions from "@/actions";

interface DiaryEditFormProps {
  diary: Diary; // 要求必填的Diary类型
}
export default function DiaryEditForm({ diary }: DiaryEditFormProps) {
  const [content, setContent] = useState(diary);
  const handleEditorChange = (event: {
    target: { name: string; value: string };
  }) => {
    const { name, value } = event.target;
    setContent((prevContent) => ({
      ...prevContent,
      [name]: value,
    }));
  };
  const editDiaryAction = actions.editDiary.bind(
    null,
    diary.id,
    content.title,
    content.description
  );
  return (
    <form action={editDiaryAction} className="space-y-4">
      <h1 className="text-center font-semibold">Edit your Diary</h1>
      <div>
        <label
          htmlFor="title"
          className="block text-gray-700 font-medium mb-2 leading-tight"
        >
          Title
        </label>
        <input
          type="text"
          name="title"
          id="title"
          value={content.title}
          onChange={handleEditorChange}
          className="w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:border-gray-500"
        />
      </div>
      <div>
        <label
          htmlFor="description"
          className="block text-gray-700 font-medium mb-2 leading-tight"
        >
          Description
        </label>
        <textarea
          name="description"
          id="description"
          value={content.description}
          onChange={handleEditorChange}
          className="min-h-32 w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:border-gray-500"
        ></textarea>
      </div>

      <button
        type="submit"
        className="bg-gray-600 text-white px-4 py-2 rounded"
      >
        Save
      </button>
    </form>
  );
}

解决方案

1. 处理查询结果的null情况(推荐)

在页面中检查查询结果,若未找到对应日记则返回404页面,同时确保传递给组件的diary是确定的Diary类型:

import { db } from "@/db";
import DiaryEditForm from "@/components/diary-edit-form";
import { notFound } from "next/navigation";

interface DiaryEditPageProps {
    params: {
        id: string;
    };
}
export default async function DiaryEditPage(props: DiaryEditPageProps) {
        const id = parseInt(props.params.id);
        const diary = await db.diary.findFirst({
            where: { id },
            });
        
        // 未找到日记时触发404
        if (!diary) {
            notFound();
        }

        // 此时diary类型已确定为Diary,可安全传递给组件
        return (
        <div>
        <DiaryEditForm diary={diary} />
        </div>
    );
}

2. 优化组件事件处理类型(可选)

组件中handleEditorChange的事件类型可更精确,避免类型模糊问题:

const handleEditorChange = (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
    const { name, value } = event.target;
    // 断言name为Diary的属性键,避免类型报错
    setContent((prevContent) => ({
      ...prevContent,
      [name as keyof Diary]: value,
    }));
};

额外提醒

不建议使用非空断言diary!强制类型转换,这种方式会隐藏潜在的null值风险,无法保证运行时的稳定性。

内容的提问来源于stack exchange,提问作者Abdullah Munshi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:15:16