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

如何实现TypeScript接口/类型在蛇形命名(snake_case)与驼峰命名(camelCase)间的双向转换?

如何实现TypeScript接口/类型在蛇形命名(snake_case)与驼峰命名(camelCase)间的双向转换?

刚好之前做项目的时候也遇到过一模一样的需求,给你整理两个核心部分:类型层面的类型别名推导(让TypeScript能正确提示驼峰/蛇形的属性)和运行时的对象转换函数(实际处理API数据的结构转换),直接就能用:

一、先搞定类型层面的映射(编译时)

首先我们需要写两个类型工具,分别处理蛇形到驼峰、驼峰到蛇形的键名转换,再递归处理嵌套的对象和数组:

// 蛇形字符串转驼峰字符串的类型工具
type SnakeToCamel<S extends string> = 
  S extends `${infer T}_${infer U}`
    ? `${T}${Capitalize<SnakeToCamel<U>>}`
    : S;

// 驼峰字符串转蛇形字符串的类型工具
type CamelToSnake<S extends string> = 
  S extends `${infer T}${infer U}`
    ? T extends Lowercase<T>
      ? `${T}${CamelToSnake<U>}`
      : `_${Lowercase<T>}${CamelToSnake<U>}`
    : S;

// 递归处理对象所有属性的类型转换,支持嵌套对象和数组
type ConvertKeys<T, Converter extends (s: string) => string> = 
  T extends Record<string, any>
    ? {
        [K in keyof T as Converter extends (s: string) => infer R ? R : never]: 
          T[K] extends Array<infer U>
            ? Array<ConvertKeys<U, Converter>>
            : ConvertKeys<T[K], Converter>
      }
    : T;

有了这几个类型工具,你就可以基于API的蛇形接口,一键生成前端用的驼峰接口,反过来也一样:

// API返回的蛇形命名接口
interface MergedReviewDetailsSnake {
  parent_review: number;
  child_reviews: number[];
}

// 自动生成前端用的驼峰命名接口
type MergedReviewDetailsCamel = ConvertKeys<MergedReviewDetailsSnake, SnakeToCamel>;
// 此时MergedReviewDetailsCamel的结构就是 { parentReview: number; childReviews: number[]; }

// 如果需要从驼峰接口生成蛇形接口也可以
// type MergedReviewDetailsSnakeAgain = ConvertKeys<MergedReviewDetailsCamel, CamelToSnake>;

二、再写运行时的转换函数(实际处理数据)

类型只是编译时的提示,实际API返回的是普通JS对象,我们需要写运行时函数来真正转换键名:

// 单个字符串:蛇形转驼峰
function snakeToCamelStr(str: string): string {
  return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
}

// 单个字符串:驼峰转蛇形
function camelToSnakeStr(str: string): string {
  return str.replace(/([A-Z])/g, '_$1').toLowerCase();
}

// 递归转换整个对象/数组:蛇形转驼峰
function convertSnakeToCamel<T>(obj: T): ConvertKeys<T, SnakeToCamel> {
  // 处理数组
  if (Array.isArray(obj)) {
    return obj.map(item => convertSnakeToCamel(item)) as unknown as ConvertKeys<T, SnakeToCamel>;
  }
  // 处理对象(排除Date等特殊对象)
  if (obj && typeof obj === 'object' && !(obj instanceof Date)) {
    return Object.fromEntries(
      Object.entries(obj).map(([key, value]) => [
        snakeToCamelStr(key),
        convertSnakeToCamel(value)
      ])
    ) as unknown as ConvertKeys<T, SnakeToCamel>;
  }
  // 基本类型直接返回
  return obj as unknown as ConvertKeys<T, SnakeToCamel>;
}

// 递归转换整个对象/数组:驼峰转蛇形
function convertCamelToSnake<T>(obj: T): ConvertKeys<T, CamelToSnake> {
  if (Array.isArray(obj)) {
    return obj.map(item => convertCamelToSnake(item)) as unknown as ConvertKeys<T, CamelToSnake>;
  }
  if (obj && typeof obj === 'object' && !(obj instanceof Date)) {
    return Object.fromEntries(
      Object.entries(obj).map(([key, value]) => [
        camelToSnakeStr(key),
        convertCamelToSnake(value)
      ])
    ) as unknown as ConvertKeys<T, CamelToSnake>;
  }
  return obj as unknown as ConvertKeys<T, CamelToSnake>;
}

三、实际使用示例

直接把API数据丢进去转换就行,TypeScript还会自动提示正确的属性名:

// 模拟API返回的蛇形数据
const apiResponse = {
  parent_review: 1001,
  child_reviews: [1002, 1003, 1004]
};

// 转成驼峰格式给前端用
const frontendData = convertSnakeToCamel(apiResponse);
// 此时frontendData.parentReview、frontendData.childReviews 都会有正确的类型提示

// 前端组装好的驼峰数据
const submitData = {
  parentReview: 1001,
  childReviews: [1002, 1003, 1005]
};

// 转成蛇形格式提交给API
const apiSubmitData = convertCamelToSnake(submitData);
// 此时apiSubmitData的结构就是 { parent_review: 1001; child_reviews: [1002, 1003, 1005]; }

一些小提示

  • 上面的函数已经处理了嵌套对象和数组的场景,比如{ user_info: { user_name: "xxx" } }会转成{ userInfo: { userName: "xxx" } }
  • 如果遇到特殊命名(比如全大写的缩写如user_id_card转userIDCard),可以调整正则或者加个特殊处理的逻辑,大部分常规场景直接用没问题
  • 类型工具和转换函数是对应的,转换后的对象类型会自动匹配,不用手动声明

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 11:53:06