ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

es-toolkit 的 toCamelCaseKeys 详解:递归将对象与数组键转换为 camelCase

es-toolkit 的 toCamelCaseKeys 详解:递归将对象与数组键转换为 camelCase es-toolkit 的 toCamelCaseKeys 详解递归将对象与数组键转换为 camelCase【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkittoCamelCaseKeys是 es-toolkit 提供的对象工具函数它将对象、嵌套对象以及数组中的对象的所有键递归转换为 camelCase小驼峰命名并返回一个全新的对象。它尤其适合处理来自后端 API 的snake_case、PascalCase或全大写命名的数据让你在接入前端代码时无需手工逐层改写字段名。读完本文你将掌握它的转换规则、递归边界、类型推导能力以及源码级实现原理。camelCase 命名规则camelCase小驼峰是一种命名约定标识符的第一个单词全部小写后续每个单词的首字母大写并直接拼接中间不使用任何分隔符。例如user_id转为userIdFIRST_NAME转为firstName。const camelCased toCamelCaseKeys(obj);使用方式toCamelCaseKeys(obj)当你需要把对象的所有键转换为 camelCase 时直接调用toCamelCaseKeys即可。嵌套对象、数组内的对象都会被递归转换。键的转换遵循以下规则snake_case→camelCase例如user_id→userIdPascalCase→camelCase例如UserId→userId全大写键 →camelCase例如FIRST_NAME→firstNameLAST→lastimport { toCamelCaseKeys } from es-toolkit/object; // 基本对象转换 const obj { user_id: 1, first_name: John, last_name: Doe }; const result toCamelCaseKeys(obj); // result 为 { userId: 1, firstName: John, lastName: Doe } // 数组内的对象也会被转换 const users [ { user_id: 1, first_name: John }, { user_id: 2, first_name: Jane }, ]; const convertedUsers toCamelCaseKeys(users); // convertedUsers 为 [{ userId: 1, firstName: John }, { userId: 2, firstName: Jane }] // 嵌套对象被完整转换 const nested { user_data: { user_id: 1, contact_info: { email_address: johnexample.com, phone_number: 123-456-7890, }, }, }; const nestedResult toCamelCaseKeys(nested); // nestedResult 为 { // userData: { // userId: 1, // contactInfo: { // emailAddress: johnexample.com, // phoneNumber: 123-456-7890 // } // } // } // PascalCase 与全大写键也会被转换 const raw { UserId: 1, FIRST_NAME: JinHo, LAST: Yeom }; const converted toCamelCaseKeys(raw); // converted 为 { userId: 1, firstName: JinHo, last: Yeom }参数objT需要将键转换为 camelCase 的对象、数组或原始值。返回值ToCamelCaseKeysT返回所有键均转换为 camelCase 的新对象。注意返回值是新对象原对象不会被修改。源码实现递归与分支处理从源码结构看toCamelCaseKeys的实现位于 src/object/toCamelCaseKeys.ts整体逻辑是对三种输入分别处理export function toCamelCaseKeysT(obj: T): ToCamelCaseKeysT { if (isArray(obj)) { return obj.map(item toCamelCaseKeys(item)) as ToCamelCaseKeysT; } if (isPlainObject(obj)) { const result {} as ToCamelCaseKeysT; const keys Object.keys(obj); for (let i 0; i keys.length; i) { const key keys[i]; const camelKey camelCase(key) as keyof typeof result; const convertedValue toCamelCaseKeys(obj[key]); result[camelKey] convertedValue as ToCamelCaseKeysT[keyof ToCamelCaseKeysT]; } return result; } return obj as ToCamelCaseKeysT; }实现要点如下数组分支通过isArray判断后用map对每个元素递归调用toCamelCaseKeys因此数组中的对象及其嵌套结构都会被转换普通对象分支通过isPlainObject判断导入自 src/predicate/isPlainObject.ts用Object.keys遍历自有可枚举键将每个键交给camelCase转换后写入新对象同时对该键的值递归转换原始值兜底非数组、非普通对象的值数字、字符串、布尔值、null、undefined等原样返回不做任何处理。键转换的底层camelCase 与单词切分键名转换最终由 src/string/camelCase.ts 完成。它先用words函数按 src/string/words.ts 中的CASE_SPLIT_PATTERN正则将字符串切分为单词数组再取第一个单词小写、后续单词首字母大写拼接export function camelCase(str: string): string { const words getWords(str); if (words.length 0) { return ; } const [first, ...rest] words; return ${first.toLowerCase()}${rest.map(word capitalize(word)).join()}; }CASE_SPLIT_PATTERN基于 Unicode 属性\p{Lu}、\p{Ll}、\p{Emoji_Presentation}等匹配单词这意味着支持 unicode 字符与 emoji。例如camelCase(HTTPRequest)会得到httpRequestcamelCase(Keep unicode )会得到keepUnicode。这也是FIRST_NAME这种全大写键能正确切成FIRST、NAME两个词的原因。类型层面ToCamelCaseKeys 的递归类型推导toCamelCaseKeys的返回值类型是ToCamelCaseKeysT定义于 src/types/ToCamelCaseKeys.ts。它是一组递归的条件类型与运行时行为严格对齐type SnakeToCamelS extends string S extends ${infer H}_${infer T} ? ${LowercaseH}${CapitalizeSnakeToCamelT} : LowercaseS; type PascalToCamelS extends string S extends ${infer F}${infer R} ? ${LowercaseF}${R} : S; type AnyToCamelS extends string S extends ${string}_${string} ? SnakeToCamelS : S extends UppercaseS ? LowercaseS : PascalToCamelS; export type ToCamelCaseKeysT T extends NonPlainObject ? T : T extends any[] ? ArrayToCamelCaseKeysT[number] : T extends Recordstring, any ? { [K in keyof T as AnyToCamelExtractK, string]: ToCamelCaseKeysT[K] } : T;类型层的三条规则与运行时分支一一对应AnyToCamel用模板字面量类型处理三种键含下划线的按SnakeToCamel递归转换全大写的整体Lowercase其余含 PascalCase仅将首字母小写映射类型{ [K in keyof T as AnyToCamel...]: ... }通过as重映射键名同时递归转换值类型因此嵌套对象和数组在编译期就能得到精确的类型NonPlainObject定义于 src/_internal/NonPlainObject.ts列出了Date、RegExp、Map、Set、Promise、Error、ArrayBuffer、各类 TypedArray、函数以及globalThis等内置对象类型这些类型直接原样通过不做键转换避免对内置对象的内部结构做无意义且危险的映射。type Response { user_id: number; first_name: string }; type Converted ToCamelCaseKeysResponse; // { userId: number; firstName: string }该类型在 docs/types/reference/objects/ToCamelCaseKeys.md 中有独立文档说明。边界行为与测试验证src/object/toCamelCaseKeys.spec.ts 用 Vitest 覆盖了完整的行为边界可作为实际使用时的参考数组内对象与对象内数组双向递归{ user_list: [...] }中数组元素的键同样被转换原始值原样返回123、string、null、undefined、true传入后均原样返回空对象与空数组{}和[]分别返回{}和[]保留原型方法值为Object.prototype.toString这类函数属性的键不会被破坏不递归非普通对象Date、Map、Set、RegExp等值只作为普通值保留created_at: date只把键转为createdAt值仍是同一个Date实例类型级验证测试通过expectTypeOf断言嵌套对象、数组、混合结构与全大写键如as const的FIRST_NAME在编译期都得到正确的 camelCase 类型。与 lodash/fp 的对比基准仓库在 benchmarks/performance/toCamelCaseKeys.bench.ts 中提供了针对深层嵌套对象的性能对比基准与lodash/fp的mapKeys(camelCase)组合在同一结构上对比lodash 方案为浅层转换。基准数据使用 Vitest 的bench运行你可以在仓库中查看该文件了解对比设置与数据结构。需要注意的是lodash/fp 方案默认只转换顶层键而 es-toolkit 的toCamelCaseKeys是深度递归转换二者行为并不完全等价。使用建议toCamelCaseKeys从 src/object/index.ts 导出可通过import { toCamelCaseKeys } from es-toolkit/object按需引入也可从es-toolkit主入口导入它返回新对象适合用于 API 响应数据的清洗层例如在请求封装里统一对响应体做toCamelCaseKeys转换再交给业务代码使用由于转换是深度递归的对于超大对象会有一定的遍历开销可结合实际数据规模评估是否需要在边缘层缓存结果若需要反向转换camelCase → snake_case仓库还提供了对应的toSnakeCaseKeys与本文的转换规则互为镜像可配合使用。【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表