typescript - TypeScript 将通用对象从蛇形转换为驼峰形
问题描述
我想编写一个函数,它接受带有蛇形键的对象并将其转换为带有驼峰键的对象。假设我们知道输入对象的类型,但希望解决方案是通用的,那么在 TypeScript 中输入此类函数的最佳方式是什么。
type InputType = {
snake_case_key_1: number,
snake_case_key_2: string,
...
}
function snakeToCamelCase(object: T): U {
...
}
可以做的最好的工作是T
什么U
?
我想U
尽可能地缩小类型,并且理想U
地基于类型T
。
理想情况下,如果T
是我的示例,InputType
我希望将 U 键入为
{
snakeCaseKey1: number,
snakeCaseKey2: string,
...
}
解决方案
解决方案
TypeScript 4.1 中的模板文字类型可以做到这一点(另见蛇案例):
type SnakeToCamelCase<S extends string> =
S extends `${infer T}_${infer U}` ?
`${T}${Capitalize<SnakeToCamelCase<U>>}` :
S
type T11 = SnakeToCamelCase<"hello"> // "hello"
type T12 = SnakeToCamelCase<"hello_world"> // "helloWorld"
type T13 = SnakeToCamelCase<"hello_ts_world"> // "helloTsWorld"
type T14 = SnakeToCamelCase<"hello_world" | "foo_bar">// "helloWorld" | "fooBar"
type T15 = SnakeToCamelCase<string> // string
type T16 = SnakeToCamelCase<`the_answer_is_${N}`>//"theAnswerIs42" (type N = 42)
然后,您将能够使用映射类型中的键重新映射来构造新的记录类型:
type OutputType = {[K in keyof InputType as SnakeToCamelCase<K>]: InputType[K]}
/*
type OutputType = {
snakeCaseKey1: number;
snakeCaseKey2: string;
}
*/
扩展
反转类型
type CamelToSnakeCase<S extends string> =
S extends `${infer T}${infer U}` ?
`${T extends Capitalize<T> ? "_" : ""}${Lowercase<T>}${CamelToSnakeCase<U>}` :
S
type T21 = CamelToSnakeCase<"hello"> // "hello"
type T22 = CamelToSnakeCase<"helloWorld"> // "hello_world"
type T23 = CamelToSnakeCase<"helloTsWorld"> // "hello_ts_world"
Pascal 案例、Kebab 案例和倒置
一旦你获得了上述类型,使用内部字符串类型 Capitalize
和在它们和其他情况之间进行转换非常简单Uncapitalize
:
type CamelToPascalCase<S extends string> = Capitalize<S>
type PascalToCamelCase<S extends string> = Uncapitalize<S>
type PascalToSnakeCase<S extends string> = CamelToSnakeCase<Uncapitalize<S>>
type SnakeToPascalCase<S extends string> = Capitalize<SnakeToCamelCase<S>>
对于烤肉串盒,将_
蛇盒类型替换为-
.
转换嵌套属性
type SnakeToCamelCaseNested<T> = T extends object ? {
[K in keyof T as SnakeToCamelCase<K & string>]: SnakeToCamelCaseNested<T[K]>
} : T
“类型实例化太深了,可能是无限的。”
很长的字符串可能会发生此错误。您可以一次性处理多个子项,以将类型递归限制在编译器可接受的范围内。例如SnakeToCamelCaseXXL
:
type SnakeToCamelCaseXXL<S extends string> =
S extends `${infer T}_${infer U}_${infer V}` ?
`${T}${Capitalize<U>}${Capitalize<SnakeToCamelCaseXXL<V>>}` :
S extends `${infer T}_${infer U}` ?
`${T}${Capitalize<SnakeToCamelCaseXXL<U>>}` :
S
注意:在第一个条件中,T
每个U
都推断一个子项,而V
推断字符串的其余部分。
更新:TS 4.5 将类型实例化深度限制从 50 提高到 100,所以这个编译器技巧对于新版本是不必要的。对于更复杂的情况,您现在还可以使用尾递归评估。
推荐阅读
- wordpress - Elementor 库:未连接(cURL 错误 28:连接超时 ...)
- android - android build.gradle 模块应用程序错误:无法解决:注释
- xaml - 如何仅在 UWP 中将 AcrylicBrush 添加到工具栏
- unix - CircleCI 运行多行命令
- parsing - 如何使用 asyncio 模块在 python 中解析网站?
- .net - 为什么我的 MessageBox 显示这么多次?
- java - PDFDomTree 在将 pdf 文件转换为 html 时未检测到空格
- android - 通过更新到 Android Studio 3.2 迁移到 AndroidX
- powershell - 删除文件和文件夹 1 级下
- ios - 没有为团队“xyz”找到具有 iTunes Connect 访问权限的帐户。App Store 分发需要itunes Connect 访问权限