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

TypeScript处理API返回snake_case映射前端PascalCase类型报错最佳实践

snake_case接口字段转前端命名格式的解决方案与最佳实践

核心问题结论

绝对不要用any类型声明接口返回数据。这种做法会完全绕过TypeScript的类型校验,后续字段拼写错误、类型不符的问题无法在编译阶段暴露,会大幅提升线上故障概率。
你当前代码报错的核心原因是:错误地将后端返回的snake_case格式数据标注为前端业务定义的User类型,而User类型本身不存在last_name、first_name属性,自然触发类型错误。

分层落地方案

1. 基础场景:单接口显式类型定义+映射

如果只有少量接口存在命名格式差异,直接为接口原始返回值定义独立类型,再做显式字段映射即可,完全不需要绕开类型校验:

// 1. 定义和后端返回完全对齐的原始类型
type ApiUser = {
  id: number
  last_name: string
  first_name: string
}

// 2. 请求时指定响应泛型,让TS自动推导res.data的类型
let users: User[] = []
const res = await axios.get<ApiUser[]>('/users')
res.data.forEach((user) => {
  users.push({
    id: user.id,
    lastName: user.last_name,
    firstName: user.first_name
  })
})
return users

2. 中大型项目:全局统一转换+类型自动映射

如果项目里大量接口都使用snake_case返回,不要每个接口重复写映射逻辑,可以做两层全局封装,一劳永逸解决命名转换问题:

  • 第一层:在axios响应拦截器中加入通用递归转换函数,把接口返回的所有snake_case字段批量转换为前端需要的驼峰/PascalCase格式,业务代码不需要再逐字段处理
  • 第二层:配套写通用TS类型工具,自动把后端snake_case的类型定义转换成前端对应的命名格式类型,不需要重复维护两套类型
    核心实现代码参考:
/**
 * 递归转换对象snake_case键为小驼峰格式,需要PascalCase可自行调整首字母大写逻辑
 */
function snakeToCamel<T>(obj: T): CamelCaseNested<T> {
  if (Array.isArray(obj)) {
    return obj.map(item => snakeToCamel(item)) as CamelCaseNested<T>
  }
  if (obj !== null && typeof obj === 'object') {
    return Object.keys(obj).reduce((acc, key) => {
      const camelKey = key.replace(/_([a-z])/g, (_, char) => char.toUpperCase())
      acc[camelKey] = snakeToCamel((obj as Record<string, unknown>)[key])
      return acc
    }, {} as Record<string, unknown>) as CamelCaseNested<T>
  }
  return obj as CamelCaseNested<T>
}

// 配套TS类型工具:自动将snake_case类型转为小驼峰类型
type CamelCase<S extends string> = S extends `${infer Head}_${infer FirstChar}${infer Tail}`
  ? `${Lowercase<Head>}${Uppercase<FirstChar>}${CamelCase<Tail>}`
  : Lowercase<S>

type CamelCaseNested<T> = T extends (infer Item)[]
  ? CamelCaseNested<Item>[]
  : T extends object
  ? { [K in keyof T as K extends string ? CamelCase<K> : K]: CamelCaseNested<T[K]> }
  : T

// 全局配置axios响应拦截器,所有响应自动做字段转换
axios.interceptors.response.use((res) => {
  res.data = snakeToCamel(res.data)
  return res
})

封装完成后,业务代码可以直接拿到符合前端类型要求的数据,不需要重复写映射逻辑:

// 业务代码示例
const res = await axios.get<CamelCaseNested<ApiUser>[]>('/users')
const users: User[] = res.data // 类型自动匹配,无报错

注意事项

如果项目接口返回结构层级极深、或者对性能要求极高,全局递归转换可能带来微小的性能开销,这种场景可以按接口模块做按需转换,也可以使用轻量的成熟转换库代替手写逻辑,但核心原则不变:禁止用any逃避类型检查,所有数据转换链路必须有明确的类型覆盖。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 01:48:33