错误处理设计模式实战:Claude Code 进阶指南
从自定义错误类、Result 模式到全局错误中间件和 React Error Boundary,用 Claude Code 打造类型安全的错误处理体系。
用 Claude Code 改善错误处理设计
恰当的错误处理与应用的健壮性息息相关。借助 Claude Code,你可以高效落地类型安全且风格一致的错误处理模式。
自定义错误类设计
> 帮我设计一组全局使用的自定义错误类。
> 要包含 HTTP 状态码映射、错误 code,以及给用户看的消息。
// errors/base.ts
export abstract class AppError extends Error {
abstract readonly statusCode: number;
abstract readonly code: string;
readonly isOperational: boolean;
constructor(message: string, isOperational = true) {
super(message);
this.name = this.constructor.name;
this.isOperational = isOperational;
Error.captureStackTrace(this, this.constructor);
}
toJSON() {
return {
error: {
code: this.code,
message: this.message,
...(process.env.NODE_ENV === "development" && { stack: this.stack }),
},
};
}
}
// errors/http.ts
export class NotFoundError extends AppError {
readonly statusCode = 404;
readonly code = "NOT_FOUND";
constructor(resource: string, id?: string) {
super(id ? `未找到 ${resource}(${id})` : `未找到 ${resource}`);
}
}
export class ValidationError extends AppError {
readonly statusCode = 400;
readonly code = "VALIDATION_ERROR";
readonly fields: Record<string, string[]>;
constructor(fields: Record<string, string[]>) {
super("存在校验错误");
this.fields = fields;
}
toJSON() {
return {
error: {
code: this.code,
message: this.message,
fields: this.fields,
},
};
}
}
export class UnauthorizedError extends AppError {
readonly statusCode = 401;
readonly code = "UNAUTHORIZED";
constructor(message = "Authentication required") {
super(message);
}
}
export class ForbiddenError extends AppError {
readonly statusCode = 403;
readonly code = "FORBIDDEN";
constructor(message = "无权限") {
super(message);
}
}
Result 类型模式
一种不靠异常、用类型安全方式处理错误的模式。
> 帮我实现 Result 类型模式。
> 成功和失败要在类型层面上可区分。
// types/result.ts
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
function ok<T>(data: T): Result<T, never> {
return { success: true, data };
}
function err<E>(error: E): Result<never, E> {
return { success: false, error };
}
// 使用示例
async function findUser(id: string): Promise<Result<User, NotFoundError>> {
const user = await db.user.findUnique({ where: { id } });
if (!user) {
return err(new NotFoundError("User", id));
}
return ok(user);
}
// 调用方
const result = await findUser("123");
if (result.success) {
console.log(result.data.name); // 类型安全地访问
} else {
console.log(result.error.message); // 错误类型也被类型保护
}
全局错误处理器
为 Express 实现一个全局错误处理中间件:
> 帮我写一个 Express 的全局错误处理中间件。
> AppError 转换成对应响应,预期外错误统一返回 500。
> 生产环境下隐藏堆栈信息。
import { Request, Response, NextFunction } from "express";
import { AppError } from "../errors/base";
export function globalErrorHandler(
err: Error,
req: Request,
res: Response,
_next: NextFunction
) {
// 日志输出
if (err instanceof AppError && err.isOperational) {
console.warn(`[${err.code}] ${err.message}`);
} else {
console.error("Unexpected error:", err);
}
// AppError 时返回定义好的响应
if (err instanceof AppError) {
return res.status(err.statusCode).json(err.toJSON());
}
// 预期外错误
res.status(500).json({
error: {
code: "INTERNAL_ERROR",
message: process.env.NODE_ENV === "production"
? "服务器发生错误"
: err.message,
},
});
}
异步错误捕获
> 帮我写一个包装器,自动捕获 Express async route handler 中的错误。
import { Request, Response, NextFunction, RequestHandler } from "express";
function asyncHandler(
fn: (req: Request, res: Response, next: NextFunction) => Promise<void>
): RequestHandler {
return (req, res, next) => {
fn(req, res, next).catch(next);
};
}
// 使用示例:不再需要 try-catch
router.get("/users/:id", asyncHandler(async (req, res) => {
const user = await userService.findById(req.params.id);
if (!user) {
throw new NotFoundError("User", req.params.id);
}
res.json({ data: user });
}));
前端 Error Boundary
> 帮我写一个 React Error Boundary,
> 根据错误类型显示不同的 UI。
import { Component, ReactNode } from "react";
interface Props {
children: ReactNode;
fallback?: (error: Error, retry: () => void) => ReactNode;
}
interface State {
error: Error | null;
}
class ErrorBoundary extends Component<Props, State> {
state: State = { error: null };
static getDerivedStateFromError(error: Error) {
return { error };
}
handleRetry = () => {
this.setState({ error: null });
};
render() {
if (this.state.error) {
if (this.props.fallback) {
return this.props.fallback(this.state.error, this.handleRetry);
}
return (
<div className="p-8 text-center">
<h2 className="text-xl font-bold text-red-600">发生错误</h2>
<p className="mt-2 text-gray-600">{this.state.error.message}</p>
<button
onClick={this.handleRetry}
className="mt-4 rounded bg-blue-500 px-4 py-2 text-white"
>
重试
</button>
</div>
);
}
return this.props.children;
}
}
更具体的调试与错误排查方法见 调试技巧完全指南,TypeScript 的类型设计可以看 TypeScript 开发技巧。从安全角度看错误信息的处理方式请参考 安全审计自动化。
总结
一致的错误处理设计能显著提升应用的健壮性与可维护性。借助 Claude Code,自定义错误类、Result 类型、全局处理器都能高效落地。
错误处理的最佳实践请看 Node.js 官方指南,Claude Code 相关请参阅 Anthropic 官方文档。
#Claude Code
#错误处理
#设计模式
#TypeScript
#健壮性
M
本文作者
Masa
深度使用 Claude Code 的工程师。运营 claudecode-lab.com——一个涵盖 10 种语言、超过 2,000 页内容的科技媒体。
相关文章
Advanced
Claude Code Agent SDK入门 ― 快速构建自主智能代理
学习如何使用Claude Code Agent SDK构建自主AI代理。涵盖环境搭建、工具定义和多步执行,附带实践代码示例。
Advanced
Claude Code 上下文管理技巧完全指南
详解如何最大限度地利用 Claude Code 的上下文窗口。涵盖 Token 优化、对话分割和 CLAUDE.md 的使用方法。
Advanced
Claude Code Hooks 完全指南:自动格式化、自动测试等实用配置
详解如何通过 Claude Code Hooks 实现自动格式化和自动测试。包含实际配置示例和真实使用场景。