Advanced

错误处理设计模式实战: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 #健壮性

让你的 Claude Code 工作流更上一层楼

50 个经过实战检验的提示词模板,现在就能复制粘贴到 Claude Code 中使用。

免费

免费 PDF:5 分钟看懂 Claude Code 速查表

关键命令、快捷键与提示词示例,整理在一页可打印的 A4 纸上。

下载 PDF
M

本文作者

Masa

深度使用 Claude Code 的工程师。运营 claudecode-lab.com——一个涵盖 10 种语言、超过 2,000 页内容的科技媒体。