前言
在日常的开发需求中,经常会碰到协作方的变量命名风格与我们自己项目中的变量命名风格不一致的情况。例如后端返回的变量命名是下划线,而前端使用的变量命名是驼峰。本文介绍了一种实用的方法将对象中的变量名由下划线转为驼峰,包括Typescript类型定义的转换,如果你有兴趣的话简单花5分钟学习一下吧~
对象命名转换
字符串转换
可以使用lodash的工具函数进行下划线/驼峰字符串之间的互转:
- lodash.snakeCase 源码地址:github.com/lodash/loda...
- lodash.camelCase 源码地址:github.com/lodash/loda...
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;
};