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

如何通过接口在反序列化时将错误字符串映射为指定枚举值?

解决方案

1. 把修正逻辑封装到枚举命名空间

不改动原有枚举定义,通过命名空间扩展枚举的转换能力,将错误值映射逻辑集中在枚举相关代码里,避免影响现有接口和泛型函数:

enum Bar {
  bar = "bar",
  qux = "qux",
}

namespace Bar {
  // 定义错误值到正确枚举值的映射表
  const errorValueMap: Record<string, Bar> = {
    "baz": Bar.bar
  };

  // 单个值转换函数
  export function fromRawValue(value: string): Bar {
    // 优先匹配正常枚举值,匹配失败则查错误映射,最后可根据业务设置默认值或抛出错误
    return Bar[value as keyof typeof Bar] ?? errorValueMap[value] ?? Bar.bar;
  }

  // 数组批量转换函数
  export function fromRawArray(values: string[]): Bar[] {
    return values.map(fromRawValue);
  }
}

// 原有接口保持不变
interface Data1 {
  foo: Bar[];
}
interface Data2 {
  foo: Bar[];
}

// 泛型fetch函数无需修改
async function fetchData<T>() {
  const response = await fetch("data.json");
  return await response.json() as T;
}

// 使用时仅需在获取数据后调用转换函数处理对应字段
async function getProcessedData1(): Promise<Data1> {
  const rawData = await fetchData<{ foo: string[] }>();
  return {
    foo: Bar.fromRawArray(rawData.foo)
  };
}

const data: Data1 = await getProcessedData1();

2. 结合类型守卫实现类型安全的转换

如果需要更强的类型校验,可通过类型守卫确保转换后的值严格符合枚举类型:

enum Bar {
  bar = "bar",
  qux = "qux",
}

// 类型守卫:判断值是否为合法Bar枚举值
function isValidBar(value: string): value is Bar {
  return Object.values(Bar).includes(value as Bar);
}

// 转换函数:处理合法值与错误值
function convertToBar(value: string): Bar {
  if (isValidBar(value)) {
    return value;
  }
  switch (value) {
    case "baz":
      return Bar.bar;
    default:
      // 可根据业务需求选择抛出错误或返回默认值
      throw new Error(`无效的Bar值:${value}`);
  }
}

// 使用方式类似,转换对应字段即可
async function getProcessedData2(): Promise<Data2> {
  const rawData = await fetchData<{ foo: string[] }>();
  return {
    foo: rawData.foo.map(convertToBar)
  };
}

3. 自定义JSON解析器(零侵入调用)

如果希望完全保留原有fetch调用方式,可替换默认的JSON解析逻辑,在解析阶段自动修正错误值:

enum Bar {
  bar = "bar",
  qux = "qux",
}

// 自定义JSON解析函数,递归遍历并修正Bar类型的错误值
function parseWithBarFix<T>(jsonStr: string): T {
  const parsed = JSON.parse(jsonStr);

  function processValue(value: any): any {
    if (Array.isArray(value)) {
      return value.map(processValue);
    }
    if (typeof value === "string") {
      // 处理错误值映射
      if (value === "baz") return Bar.bar;
      // 保留合法枚举值
      if (Object.values(Bar).includes(value)) return value;
    }
    if (typeof value === "object" && value !== null) {
      for (const key in value) {
        value[key] = processValue(value[key]);
      }
    }
    return value;
  }

  return processValue(parsed) as T;
}

// 仅修改fetchData内的解析逻辑,调用方式完全不变
async function fetchData<T>() {
  const response = await fetch("data.json");
  const jsonStr = await response.text();
  return parseWithBarFix<T>(jsonStr);
}

// 原有调用代码无需任何改动
const data: Data1 = await fetchData<Data1>();

方案对比

  • 方案1:逻辑集中,对现有代码改动最小,适合需要明确控制转换流程的场景。
  • 方案2:类型安全性更高,能提前拦截非法值,适合对类型严谨性要求高的业务。
  • 方案3:调用方式零侵入,但需注意递归遍历的边界情况(如嵌套对象、其他类型字段的兼容)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 11:21:17