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

前言

在日常的开发需求中,经常会碰到协作方的变量命名风格与我们自己项目中的变量命名风格不一致的情况。例如后端返回的变量命名是下划线,而前端使用的变量命名是驼峰。本文介绍了一种实用的方法将对象中的变量名由下划线转为驼峰,包括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;
};
相关推荐
黑客老陈11 分钟前
新手小白如何挖掘cnvd通用漏洞之存储xss漏洞(利用xss钓鱼)
运维·服务器·前端·网络·安全·web3·xss
正小安16 分钟前
Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
前端·vite
暴富的Tdy44 分钟前
【CryptoJS库AES加密】
前端·javascript·vue.js
neeef_se44 分钟前
Vue中使用a标签下载静态资源文件(比如excel、pdf等),纯前端操作
前端·vue.js·excel
m0_748235611 小时前
web 渗透学习指南——初学者防入狱篇
前端
z千鑫1 小时前
【前端】入门指南:Vue中使用Node.js进行数据库CRUD操作的详细步骤
前端·vue.js·node.js
m0_748250742 小时前
Web入门常用标签、属性、属性值
前端
m0_748230442 小时前
SSE(Server-Sent Events)返回n ,前端接收数据时被错误的截断【如何避免SSE消息中的换行符或回车符被解释为事件消息的结束】
前端
生产队队长3 小时前
项目练习:element-ui的valid表单验证功能用法
前端·vue.js·ui