0Pricing
tRPC End-to-End Type Safe APIs · 课时

自定义错误类型

从后端定义并抛出自定义错误类型,并确保它们正确传递到前端。

自定义错误类型 是 CoddyKit 上的免费 tRPC End-to-End Type Safe APIs 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 tRPC End-to-End Type Safe APIs 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 tRPC End-to-End Type Safe APIs 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Why Custom Error Types?

In tRPC, we often use TRPCError for handling issues. But sometimes, you need more specific error types.

  • Clarity: Custom errors make your code clearer about what went wrong.
  • Specific Handling: Allows the frontend to react differently to distinct error conditions.
  • Better Debugging: Provides more context than a generic error.

Let's learn how to define and use them!

Basic Custom Error Class

At its simplest, a custom error is a class that extends JavaScript's built-in Error class. This ensures it behaves like a standard error.

It usually takes a message and sets its own name property.

class MyCustomError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'MyCustomError';
  }
}

function main() {
  try {
    throw new MyCustomError('Something specific went wrong!');
  } catch (error) {
    if (error instanceof MyCustomError) {
      console.log(`Caught: ${error.name} - ${error.message}`);
    } else {
      console.log(`Caught generic error: ${error.message}`);
    }
  }
}

main();

tRPC's TRPCError

For tRPC to correctly understand and propagate errors, your custom errors should extend TRPCError from @trpc/server.

TRPCError requires an object with a code (e.g., 'NOT_FOUND', 'BAD_REQUEST') and a message. This code helps the client understand the error type.

Defining a tRPC Custom Error

Here's how you define a custom error for tRPC, ensuring it extends TRPCError and sets a relevant status code.

This example creates a UserNotFoundError. Notice we pass the tRPC code to the super() constructor.

import { TRPCError } from '@trpc/server';

class UserNotFoundError extends TRPCError {
  constructor(userId: string) {
    super({
      code: 'NOT_FOUND',
      message: `User with ID '${userId}' not found.`
    });
    this.name = 'UserNotFoundError';
  }
}

function main() {
  try {
    throw new UserNotFoundError('user-123');
  } catch (error) {
    if (error instanceof TRPCError) {
      console.log(`Error Code: ${error.code}`);
      console.log(`Error Message: ${error.message}`);
    }
  }
}

main();

Throwing Custom Errors (Backend)

Once defined, you can throw your custom error directly within your tRPC procedures (queries or mutations). tRPC will automatically catch it and send it to the client.

This allows your backend logic to signal specific issues clearly.

import { publicProcedure, router } from './trpc'; // Assume trpc setup
import { TRPCError } from '@trpc/server';

class UserNotFoundError extends TRPCError {
  constructor(userId: string) {
    super({ code: 'NOT_FOUND', message: `User ${userId} not found.` });
    this.name = 'UserNotFoundError';
  }
}

const appRouter = router({
  getUser: publicProcedure
    .input(z.string())
    .query(async ({ input: userId }) => {
      // Simulate database lookup
      if (userId === 'nonexistent') {
        throw new UserNotFoundError(userId); // Throw our custom error!
      }
      return { id: userId, name: `User ${userId}` };
    }),
});

// Note: `z` for Zod input validation is assumed here
// The router itself is not runnable without a full server context.

Frontend: Receiving Errors

On the frontend, when a tRPC procedure fails, the client-side tRPC library will throw an instance of TRPCClientError.

This error object contains the code and message from your backend TRPCError, allowing you to identify the specific issue.

Frontend: Identifying Custom Errors

To handle specific custom errors on the client, you can use a try...catch block and inspect the error object.

  • Check error.data.code: This is the most reliable way as it's directly from the TRPCError code.
  • Check error.message: Less reliable, but can be used for specific messages.
  • instanceof (with shared types): If you share the custom error class definition between client and server, you can use instanceof. This is common in monorepos.

Frontend Example: Handling UserNotFoundError

Here's how a React component (or similar frontend logic) might handle our UserNotFoundError using the error.data.code property.

This allows you to display a user-friendly message specific to the error.

import { trpc } from './utils/trpc'; // Assume trpc client setup

function UserProfile({ userId }: { userId: string }) {
  const { data, error, isLoading } = trpc.getUser.useQuery(userId);

  if (isLoading) {
    return '<p>Loading user data...</p>';
  }

  if (error) {
    if (error.data?.code === 'NOT_FOUND') {
      return `<p>User with ID <b>${userId}</b> does not exist.</p>`;
    } else {
      return `<p>An unexpected error occurred: ${error.message}</p>`;
    }
  }

  return `<h1>Welcome, ${data?.name}!</h1>`;
}

function main() {
  // This function simulates component usage.
  // In a real app, trpc.getUser.useQuery would trigger an API call.
  console.log('Simulating UserProfile for existing user...');
  // Assume UserProfile('user-123') would render 'Welcome, User user-123!'

  console.log('Simulating UserProfile for nonexistent user...');
  // Assume UserProfile('nonexistent') would render 'User with ID nonexistent does not exist.'
}

main();

Quick Check

Which of the following are good reasons to define and use custom error types in tRPC, especially when extending TRPCError?

Recap: Custom Error Types

Great job! You've learned how to leverage custom error types in tRPC:

  • Extend TRPCError: For tRPC to correctly propagate your errors.
  • Specify code: Use tRPC's error codes (e.g., 'NOT_FOUND') for standardization.
  • Throw on Backend: Signal specific issues from your procedures.
  • Catch on Frontend: Use error.data.code for precise error handling.

This approach leads to more robust and user-friendly applications by clearly communicating backend issues to the client.

常见问题解答

「自定义错误类型」课时是免费的吗?

是的 — 「自定义错误类型」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 tRPC End-to-End Type Safe APIs 课程的其余内容,请升级到 CoddyKit PRO。 tRPC End-to-End Type Safe APIs 课程共包含 4 节课。

「自定义错误类型」这节课中我会学到什么?

从后端定义并抛出自定义错误类型,并确保它们正确传递到前端。 你通过在浏览器中直接运行的动手代码来练习 tRPC End-to-End Type Safe APIs,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 tRPC End-to-End Type Safe APIs 需要有经验吗?

无需任何先前经验。CoddyKit 上的 tRPC End-to-End Type Safe APIs 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「自定义错误类型」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 tRPC End-to-End Type Safe APIs 课中编写并运行代码吗?

能。每节 tRPC End-to-End Type Safe APIs 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 优雅地处理 tRPC 错误
  2. 自定义错误类型
  3. 用于序列化的数据转换器
  4. 格式化错误与字段级验证反馈
← 返回 tRPC End-to-End Type Safe APIs