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

tRPC+Prisma组件增删Record时类型错误求助

解决tRPC Mutation调用的类型错误问题

问题描述

在React组件中实现创建和删除Prisma记录功能时,路由配置无错误,但组件调用mutation时出现类型不匹配错误,报错集中在创建和删除任务的参数传递环节。

错误信息

Argument of type '{ input: { title: string; content: string; assigneeId: string; }; }' is not assignable to parameter of type 'void'.ts(2345)
Argument of type '{ id: string; }' is not assignable to parameter of type 'void'.ts(2345)

相关代码

Tasks.ts(路由定义)

import { z } from "zod";

export const TaskCreateInput = z.object({
  title: z.string(),
  content: z.string(),
  assigneeId: z.string(),
});
export const TaskDeleteInput = z.object({
  id: z.string(),
});

import {
    createTRPCRouter,
    publicProcedure,
  } from "~/server/api/trpc";

export const tasksRouter = createTRPCRouter({
  getAll: publicProcedure.query(({ ctx }) => {
    return ctx.prisma.task.findMany();
  }),  
  createTask: publicProcedure.mutation(({ ctx, input }) => {
    const validatedInput = TaskCreateInput.parse(input);
    return ctx.prisma.task.create({
      data: validatedInput,
    });
  }),
  deleteTask: publicProcedure.mutation(({ ctx, input }) => {
    const validatedInput = TaskDeleteInput.parse(input);
    return ctx.prisma.task.delete({
      where: {
        id: validatedInput.id,
      },
    });
  }),
});

Maintenance.tsx(React组件)

import React, {useState } from "react";

import { api } from "~/utils/api";
import type { TaskCreateInput, TaskDeleteInput } from "~/server/api/routers/tasks";

const Maintenance = () => {
  const { data } = api.tasks.getAll.useQuery();
  const createTaskMutation = api.tasks.createTask.useMutation();
  const deleteTaskMutation = api.tasks.deleteTask.useMutation();

  const [title, setTitle] = useState("");
  const [content, setContent] = useState("");
  const [assigneeId, setAssigneeId] = useState("");

  const handleCreateTask = () => {
    createTaskMutation.mutate({ input: { title, content, assigneeId } }, {
      onSuccess: () => {
        setTitle("");
        setContent("");
        setAssigneeId("");
      },
    });
  };
  const handleDeleteTask = (id: string) => {
    deleteTaskMutation.mutate({ id: id }, {
      onSuccess: () => {
        // handle success
      },
    });
  };

  return (
    <> 
    <div className="mb-4">
        <input className="mr-2" type="text" placeholder="Title" value={title} onChange={(e) => setTitle(e.target.value)}/>
        <input className="mr-2" type="text" placeholder="Content" value={content} onChange={(e) => setContent(e.target.value)}/>
        <input className="mr-2" type="text" placeholder="Asignee" value={assigneeId} onChange={(e) => setAssigneeId(e.target.value)}/>
        <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" onClick={handleCreateTask}>
            Add Task
        </button>
    </div>

      {data?.map((task) => (
        <div key={task.id} className="max-w-sm rounded overflow-hidden shadow-lg mb-4 flex flex-row bg-red-500">
          <div className="px-6 py-4">
            <div className="font-bold text-xl mb-2">{task.title}</div>
            <p className="font-light text=gray-700 text-base">{task.content}</p>
            <h2>Assigned to: {task.assigneeId}</h2>
          </div>
          <button className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded" onClick={() => handleDeleteTask(task.id)}>
            Delete
          </button>
        </div>
      ))}
    </>
  );
};

export default Maintenance;

解决方案

1. 修正tRPC路由的输入schema配置

问题根源是tRPC的publicProcedure未明确指定输入schema,导致客户端生成的mutation类型默认参数为void,无法匹配传入的对象。需要在路由定义中为每个mutation添加.input()方法绑定对应的Zod schema:

修改后的Tasks.ts中mutation部分:

createTask: publicProcedure
  .input(TaskCreateInput)
  .mutation(({ ctx, input }) => {
    // tRPC会自动验证输入,无需手动调用parse
    return ctx.prisma.task.create({
      data: input,
    });
  }),
deleteTask: publicProcedure
  .input(TaskDeleteInput)
  .mutation(({ ctx, input }) => {
    return ctx.prisma.task.delete({
      where: {
        id: input.id,
      },
    });
  }),

2. 调整客户端mutation调用的参数格式

移除不必要的input包裹字段,直接传入符合schema定义的对象:

修改后的Maintenance.tsx中处理函数部分:

const handleCreateTask = () => {
  createTaskMutation.mutate({ title, content, assigneeId }, {
    onSuccess: () => {
      setTitle("");
      setContent("");
      setAssigneeId("");
    },
  });
};
const handleDeleteTask = (id: string) => {
  deleteTaskMutation.mutate({ id }, {
    onSuccess: () => {
      // handle success
    },
  });
};

说明

  • tRPC通过.input()绑定schema后,会自动完成输入验证和类型推断,客户端调用时就能获得正确的参数类型提示,避免类型错误。
  • 移除手动的parse调用,简化代码逻辑,同时利用tRPC内置的验证机制保证输入合法性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 21:35:42