实战小技巧:下划线转驼峰篇

前言

在日常的开发需求中,经常会碰到协作方的变量命名风格与我们自己项目中的变量命名风格不一致的情况。例如后端返回的变量命名是下划线,而前端使用的变量命名是驼峰。本文介绍了一种实用的方法将对象中的变量名由下划线转为驼峰,包括Typescript类型定义的转换,如果你有兴趣的话简单花5分钟学习一下吧~

对象命名转换

字符串转换

可以使用lodash的工具函数进行下划线/驼峰字符串之间的互转:

perl 复制代码
_.snakeCase('Foo Bar');
// => 'foo_bar'
 
_.snakeCase('fooBar');
// => 'foo_bar'
 
_.snakeCase('--FOO-BAR--');
// => 'foo_bar'

_.camelCase('Foo Bar');
// => 'fooBar'
 
_.camelCase('--foo-bar--');
// => 'fooBar'
 
_.camelCase('__FOO_BAR__');
// => 'fooBar'

工具函数🔧

typescript 复制代码
function transformObjectKeys<T extends Record<string, any>, K>(
  input: T,
  keyTransformer: (key: string) => string
): K {
  // 确保输入是对象
  if (input && typeof input === 'object' && !Array.isArray(input)) {
    const result: Record<string, any> = {};

    for (const key of Object.keys(input)) {
      const transformedKey = keyTransformer(key); // 使用转换函数生成新键
      const value = input[key];

      // 递归处理嵌套对象
      if (value && typeof value === 'object' && !Array.isArray(value)) {
        result[transformedKey] = transformObjectKeys(value, keyTransformer);
      } else {
        result[transformedKey] = value;
      }
    }

    return result as K;
  }

  // 如果不是对象,直接返回原始输入
  return input as unknown as K;
}


function formatApiResponse<T, K>(
  response: T,
  keyTransformer: (key?: string) => string = camelCase,
  deepClone = true
): K {
  const input = deepClone ? cloneDeep(response) : response;
  return transformObjectKeys(input, keyTransformer);
}

function formatApiRequest<T, K>(
  requestData: T,
  keyTransformer: (key?: string) => string = snakeCase,
  deepClone = false
): K {
  const input = deepClone ? cloneDeep(requestData) : requestData;
  return transformObjectKeys(input, keyTransformer) as K;
}

使用示例:

typescript 复制代码
const formattedResponse = formatApiResponse(apiResponse);
const apiResponse = { first_name: "John"};

// 调用 formatApiResponse 
const formattedResponse = formatApiResponse(apiResponse); console.log(formattedResponse);
// { firstName: "John"}

类型命名转换

除了可以将对象的成员变量命名进行下划线/驼峰互转之外,typescript类型也可以进行转换。 关于类型体操的前置学习文档,有兴趣可以看一下:

www.typescriptlang.org/docs/handbo... www.typescriptlang.org/docs/handbo...

下划线转驼峰

typescript 复制代码
// 将 Snake_Case 转换为 PascalCase
type SnakeToPascalCase<T extends string> = 
  T extends `${infer Head}_${infer Tail}`
    ? `${Capitalize<Head>}${SnakeToPascalCase<Tail>}`
    : Capitalize<T>;

// 将 Snake_Case 转换为 camelCase
type SnakeToCamelCase<T extends string> = 
  T extends `${infer Head}_${infer Tail}`
    ? `${Lowercase<Head>}${SnakeToPascalCase<Tail>}`
    : T;
    
// 将对象中的键从 Snake_Case 转为 camelCase,并递归处理子对象或数组
type SnakeToCamelCasedData<T> = T extends Array<infer U>
  ? SnakeToCamelCasedData<U>[]
  : T extends object
  ? {
      [K in keyof T as SnakeToCamelCase<Extract<K, string>>]: SnakeToCamelCasedData<T[K]>;
    }
  : T;

使用示例:

typescript 复制代码
interface SnakeCaseData {
  user_name: string;
  user_age: number;
}

// 将类型转换为 camelCase
type CamelCasedData = SnakeToCamelCasedData<SnakeCaseData>;

// 转换后的类型
type CamelCasedData = {
  userName: string;
  userAge: number;
};

驼峰转下划线

typescript 复制代码
// 将 camelCase 转换为 snake_case
type CamelToSnakeCase<T extends string> = T extends `${infer Char}${infer Rest}`
  ? `${Char extends Uppercase<Char> ? `_${Lowercase<Char>}` : Char}${CamelToSnakeCase<Rest>}`
  : T;

// 将对象中的键从 camelCase 转换为 snake_case,并递归处理子对象或数组
export type CamelToSnakeCasedData<T> = 
  T extends (...args: any[]) => any // 如果是函数类型,直接返回原类型
    ? T
    : T extends Array<infer U> // 如果是数组,递归处理每个元素
    ? CamelToSnakeCasedData<U>[]
    : T extends object // 如果是对象,递归处理每个键和值
    ? {
        [K in keyof T as CamelToSnakeCase<Extract<K, string>>]: CamelToSnakeCasedData<T[K]>;
      }
    : T; // 如果是基础类型,直接返回原类型

使用示例:

typescript 复制代码
interface CamelCaseData {
  userName: string;
  userAge: number;
}

// 将类型转换为 snakeCase
type SnakeCasedData = CamelToSnakeCasedData<CamelCaseData>;

// 转换后的类型
type SnakeCasedData = {
  user_name: string;
  user_age: number;
};
相关推荐
AI大模型-小华38 分钟前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子3 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅3 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni3 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学5 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端
赵庆明老师5 小时前
Vben精讲:21-详解web-antd:tsconfig.json
前端·json·vim
wc885 小时前
微软EDGE浏览器功能学习
前端·学习·edge
Csvn6 小时前
🎯 原生 `<dialog>` 元素:终于可以扔掉一半的自定义弹窗组件了?
前端
Csvn6 小时前
🎨 CSS @layer:用「层叠优先级」终结样式打架的世纪难题
前端