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

如何从API错误对象生成TypeScript的RestError接口实例

如何优雅生成符合TypeScript接口的RestError实例(处理非合法JSON的API错误返回)

API返回的错误数据格式类似JS对象字面量,而非合法JSON:

error: { message: "entry doesn't exist", code: '4', target: 'uuid' }

需要将其转换为符合以下TypeScript接口的类型化实例:

export interface RestError {
  error: {
    target: string;
    message: string;
    code: string;
    arguments?: {
      message: string;
      code: string;
    }[];
  };
}

直接使用JSON.parse会抛出SyntaxError,目前采用手动工具函数填充,以下是几种更优雅规范的实现方式:

方案1:使用JSON5解析非严格JSON格式

JSON5是专门支持JS风格对象字面量的解析库,允许无引号的键、单引号字符串等非严格JSON语法,无需自己写复杂正则修复格式。

步骤:

  1. 安装JSON5:
npm install json5
# 或 yarn add json5
  1. 解析并转换为RestError实例:
import JSON5 from 'json5';
import type { RestError } from './your-interface-path';

function parseRestError(rawErrorText: string): RestError {
  // 给原始内容包裹外层对象(API返回的是`error: {...}`而非完整对象)
  const wrappedText = `{${rawErrorText.trim()}}`;
  // 使用JSON5解析非严格格式
  const parsed = JSON5.parse(wrappedText);

  // 类型转换与适配接口
  return {
    error: {
      target: parsed.error.target,
      message: parsed.error.message,
      code: String(parsed.error.code), // 强制转为字符串匹配接口类型
      arguments: parsed.error.arguments?.map((arg: any) => ({
        message: arg.message,
        code: arg.code
      })) ?? undefined
    }
  };
}

这个方案简洁安全,能处理绝大多数非严格JSON场景,是最推荐的实现方式。

方案2:类型安全的手动转换函数(无第三方依赖)

如果无法引入第三方库,可编写兼具格式修复、解析和类型校验的工具函数,确保生成的实例严格符合RestError接口:

import type { RestError } from './your-interface-path';

function toRestError(rawErrorText: string): RestError {
  // 步骤1:修复格式为合法JSON
  let fixedText = rawErrorText.trim();
  // 包裹外层对象
  if (!fixedText.startsWith('{')) {
    fixedText = `{${fixedText}}`;
  }
  // 给无引号的键添加双引号
  fixedText = fixedText.replace(/(\w+):/g, '"$1":');
  // 将单引号替换为双引号,并转义字符串内的单引号
  fixedText = fixedText.replace(/'/g, '\\"');

  // 步骤2:解析JSON
  let parsed: unknown;
  try {
    parsed = JSON.parse(fixedText);
  } catch (err) {
    throw new Error(`解析错误数据失败: ${(err as Error).message}`);
  }

  // 步骤3:类型校验与转换
  if (typeof parsed !== 'object' || parsed === null || !('error' in parsed)) {
    throw new Error('错误数据结构不符合预期');
  }

  const errorData = parsed.error as unknown;
  if (typeof errorData !== 'object' || errorData === null) {
    throw new Error('error字段必须为对象');
  }

  const { target, message, code, arguments: args } = errorData as {
    target?: unknown;
    message?: unknown;
    code?: unknown;
    arguments?: unknown;
  };

  // 校验必填字段类型
  if (typeof target !== 'string' || typeof message !== 'string') {
    throw new Error('target或message字段缺失或类型错误');
  }
  if (typeof code !== 'string' && typeof code !== 'number') {
    throw new Error('code字段必须为字符串或数字');
  }

  // 处理可选的arguments数组
  let processedArgs: RestError['error']['arguments'] | undefined;
  if (Array.isArray(args)) {
    processedArgs = args.filter(arg => 
      typeof arg === 'object' && arg !== null &&
      typeof (arg as any).message === 'string' &&
      typeof (arg as any).code === 'string'
    ).map(arg => ({
      message: (arg as any).message,
      code: (arg as any).code
    }));
    // 空数组转为undefined(适配可选字段)
    processedArgs = processedArgs.length > 0 ? processedArgs : undefined;
  }

  return {
    error: {
      target,
      message,
      code: String(code),
      arguments: processedArgs
    }
  };
}

这个方案完全无依赖,同时通过类型校验保证输出安全性,适合对依赖有严格限制的场景。

方案3:谨慎使用eval(仅信任内部API时)

如果API是完全可控的内部服务,可以使用eval直接解析JS对象字面量,但存在注入风险,不推荐对外暴露的服务使用:

import type { RestError } from './your-interface-path';

function parseRestErrorWithEval(rawErrorText: string): RestError {
  try {
    // 包裹为表达式避免语法错误
    const parsed = eval(`(${rawErrorText.trim()})`);
    return {
      error: {
        target: parsed.error.target,
        message: parsed.error.message,
        code: String(parsed.error.code),
        arguments: parsed.error.arguments ?? undefined
      }
    };
  } catch (err) {
    throw new Error(`解析错误失败: ${(err as Error).message}`);
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 19:15:03