type Capital<T extends string> = T extends `${infer R}${infer rest}` ? R extends '_' ? Capital<Capitalize<rest>> : `${R}${Capital<rest>}` : T
type Camelize<T> = T extends any[] ? (T extends [infer R, ...infer rest] ? [Camelize<R>, ...Camelize<rest>] : []) :
T extends object ? {
[K in keyof T as K extends string ? Capital<K> : K]: Camelize<T[K]>
} : T
Solution by ouzexi #34276
type Camelize<T extends object> = {
[P in keyof T as CamelizeString<P & string>]: T[P] extends any[]
? CamelizeArr<T[P]>
: T[P] extends object
? Camelize<T[P]>
: T[P];
};
type CamelizeString<S extends string> = S extends `${infer Pre}_${infer Rest}`
? `${Pre}${CamelizeString<Capitalize<Rest>>}`
: S;
type CamelizeArr<T extends any[]> = T extends [infer L, ...infer R]
? [Camelize<L & object>, ...CamelizeArr<R>]
: [];
Solution by Vampirelee #32630
type SnakeToCamel<T extends string, R extends string = ''> = T extends `${infer F}_${infer L}`
? SnakeToCamel<Capitalize<L>, `${R}${F}`>
: `${R}${T}`
type Camelize<T extends object> = T extends any[]
? { [K in keyof T]: T[K] extends object ? Camelize<T[K]> : T[K] }
: { [K in keyof T as SnakeToCamel<K & string>]: T[K] extends object ? Camelize<T[K]> : T[K] }
Solution by Heonys #32392
type CamelCase<S extends string> = S extends `${infer L}_${infer R1}${infer R2}`
? Uppercase<R1> extends Lowercase<R1>
? `${Lowercase<L>}_${CamelCase<`${R1}${R2}`>}`
: `${Lowercase<L>}${Uppercase<R1>}${CamelCase<R2>}`
: Lowercase<S>;
type Camelize<T> = T extends any[]
? { [K in keyof T]: Camelize<T[K]> }
: keyof T extends never
? T
: { [K in keyof T as CamelCase<K & string>]: Camelize<T[K]> };
Solution by vangie #32242
// 解答をここに記入
type SnakeToCamel<T> = T extends `${infer F}_${infer Rest}` ? `${F}${SnakeToCamel<Capitalize<Rest>>}` : T
type Camelize<T> = T extends unknown[]
? { [P in keyof T]: Camelize<T[P]>}
: T extends object
? { [P in keyof T as SnakeToCamel<P> ] : Camelize<T[P]>}
: T
SnakeToCamel<T>
は、snake_case を camelCase に変換します。
(愚直にやると以下のような実装などが考えられますが、上記のようにCapitalize を使うと楽です。)
type SnakeToCamel<T, ShouldBeUpperCase = false> = T extends `${infer F}${infer Rest}` ? F extends "_" ? SnakeToCamel<Rest, true> : `${ShouldBeUpperCase extends true ? Uppercase<F> : F}${SnakeToCamel<Rest>}` : ''
Camelize
については、object の各 key を、as で camelCase に変換する動作を再帰的に行えばいいので、
type Camelize<T> =
T extends object
? { [P in keyof T as SnakeToCamel<P> ] : Camelize<T[P]>}
: T
が基本の形となります。
しかし、これだと、今回のテストケースにある array のような配列に対応できないので、
type cases = [
Expect<Equal<
Camelize<{
some_prop: string
prop: { another_prop: string }
// ここに対応できない
array: [
{ snake_case: string },
{ another_element: { yet_another_prop: string } },
{ yet_another_element: string },
]
}>,
{
someProp: string
prop: { anotherProp: string }
// ここに対応できない
array: [
{ snakeCase: string },
{ anotherElement: { yetAnotherProp: string } },
{ yetAnotherElement: string },
]
}
>>,
]
配列の場合だけ、自身の key を変換せずに子に再帰を繋いであげる必要があります。 よって最終的な解答は
type Camelize<T> = T extends unknown[]
? { [P in keyof T]: Camelize<T[P]>}
: T extends object
? { [P in keyof T as SnakeToCamel<P> ] : Camelize<T[P]>}
: T
のようになります。
Solution by Kakeru-Miyazaki #30967
type UnderscoreToCamelCase<T extends string> =
T extends `${infer A}_${infer B}${infer C}`
? UnderscoreToCamelCase<`${A}${Capitalize<B>}${C}`>
: T
type CamelizeArray<T extends unknown[]> = T extends [infer First extends Record<string, any>, ...infer Rest]
? [Camelize<First>, ...CamelizeArray<Rest>]
: []
type Camelize<T extends Record<string, any>> = {
[K in keyof T as K extends string ? UnderscoreToCamelCase<K> : K]: T[K] extends unknown[]
? CamelizeArray<T[K]>
: T[K] extends object ? Camelize<T[K]> : T[K]
}
Solution by jjswifty #30894
type CamelizeKey<T extends string> = T extends `${infer F}_${infer C}${infer R}` ? `${F}${Capitalize<C>}${CamelizeKey<R>}` : T
type ForEach<T extends Object[]> = T extends [infer First,...infer Rest] ? [Camelize<First>,...ForEach<Rest extends Object[] ? Rest : never>] : []
type Camelize<T extends any> = T extends Object[] ? ForEach<T>: T extends Object ? {
[Key in keyof T as CamelizeKey<Key extends string ? Key : never>]: Camelize<T[Key]>
} : T
Solution by idebbarh #30778
// your answers
type ToCame<T> = T extends `${infer First}_${infer Rest}` ? ToCame<`${First}${Capitalize<Rest>}`> : T
type DoActionAry<T extends unknown[]> = T extends [infer First, ...infer Rest] ? [Camelize<First>, ...DoActionAry<Rest>] : []
type Camelize<T> = T extends object ? {
[Key in keyof T as ToCame<Key>]: T[Key] extends any[] ? DoActionAry<T[Key]> : T[Key] extends object ? Camelize<T[Key]> : T[Key]
} : T
Solution by 437204933 #29701
// your answers
type ToCame<T> = T extends `${infer First}_${infer Rest}` ? ToCame<`${First}${Capitalize<Rest>}`> : T
type DoActionAry<T extends unknown[]> = T extends [infer First, ...infer Rest] ? [Camelize<First>, ...DoActionAry<Rest>] : []
type Camelize<T> = T extends object ? {
[Key in keyof T as ToCame<Key>]: T[Key] extends any[] ? DoActionAry<T[Key]> : T[Key] extends object ? Camelize<T[Key]> : T[Key]
} : T
type GetPath<SPath extends string> = SPath extends `${infer Key}.${infer Rest}` ? [Key, ...GetPath<Rest>] : [SPath]
type DeepPick<Obj extends object, SPath extends string> = UnionToEx<FindObj<Obj, GetPath<SPath>>
Solution by 437204933 #29700
[1383]
type CamelCase<S> = S extends `${infer P}_${infer W}` ? `${P}${CamelCase<Capitalize<W>>}` : S;
type FormatArrayItem<T extends any[]> = T extends [infer P, ...infer W] ? [Camelize<P>, ...FormatArrayItem<W>] : T;
type FormatObjectItem<T extends Record<any, any>> = {
[P in keyof T as P extends string ? CamelCase<P> : P]: T[P] extends Record<any, any> ? Camelize<T[P]> : T[P];
};
export type Camelize<T extends any[] | Record<any, any>> = T extends any[]
? FormatArrayItem<T>
: T extends Record<any, any>
? FormatObjectItem<T>
: T;
Solution by fakestudy #29447
// 你的答案
type convertUnderscoreToCamelCase<T> = T extends `${infer F}_${infer R}` ? `${F}${Capitalize<convertUnderscoreToCamelCase<R>>}` : T
type TraverseTuple<T extends any[], Result extends any[] = []> = T extends [infer Head extends Record<string, any>, ...infer Rest]
? TraverseTuple<Rest, [...Result, Camelize<Head>]>
: Result;
type test = convertUnderscoreToCamelCase<'ws_wzc'>
type Camelize<T extends Record<string, any>> = {[k in keyof T as convertUnderscoreToCamelCase<k>]:
T[k] extends Record<string, any> ?
T[k] extends any[] ? TraverseTuple<T[k]> :
Camelize<T[k]>
: T[k]
}
Solution by WangZiChu199910252255 #29084
The as CamelizeStr<K>
clause should have no effect for tuple types where K
is 0
, 1
, etc. But it makes the mapped type non-homomorphic, which means that it prevents tuples and arrays from coming through as tuples and arrays. Hence the check for extends any[]
and a homomorphic mapped type (i.e. without the as
) in that case.
Using a homomorphic mapped type has some nice knock-on properties like preserving the labels on tuple elements, which #1403 does not.
type CamelizeStr<T extends PropertyKey> =
T extends `${infer Start}_${infer Rest}`
? `${Start}${Capitalize<CamelizeStr<Rest>>}`
: T
type Camelize<T> = T extends any[]
? { [K in keyof T]: Camelize<T[K]> }
: {
[K in keyof T as CamelizeStr<K>]: Camelize<T[K]>
}
Example of preserving labels:
type T = Camelize<{
some_prop: string
prop: { another_prop: string }
array: [
el1: { snake_case: string },
el2: { readonly another_element: { yet_another_prop: string } },
el3: { yet_another_element: string }
]
}>
Solution by danvk #28685
type IsAlphabet<T extends string> = Lowercase<T> extends Uppercase<T>
? false
: true
type CamelCase<S extends string> = S extends `${infer X}_${infer Y}${infer Z}`
// If Y is a symbol (not alphabetic) then keep keep that in and don't change it
? IsAlphabet<Y> extends false
? `${Lowercase<X>}_${CamelCase<`${Y}${Z}`>}`
// Else capitalize and append it
: `${Lowercase<X>}${Uppercase<Y>}${CamelCase<Z>}`
: Lowercase<S>
type Camelize<T> = T extends unknown[]
? { [K in keyof T]: T[K] extends object ? Camelize<T[K]> : T[K] }
: { [K in keyof T as CamelCase<K & string>]: T[K] extends object ? Camelize<T[K]> : T[K] }
Solution by HubooDeclan #27063
type SnakeToCamel<S> = S extends `${infer L}_${infer U}${infer R}`
? `${L}${Uppercase<U>}${SnakeToCamel<R>}`
: S;
type CamelizeArray<T> = T extends [infer F, ...infer R]
? [Camelize<F>, ...CamelizeArray<R>]
: [];
type Camelize<T> = {
[K in keyof T as SnakeToCamel<K>]: T[K] extends unknown[]
? CamelizeArray<T[K]>
: T[K] extends object
? Camelize<T[K]>
: T[K];
};
Solution by JohnLi1999 #25783
type CamelizeOne<T extends string> = T extends `${infer P}_${infer R}` ? `${P}${Capitalize<CamelizeOne<R>>}` : T;
type CamelizeArray<T extends any[]> = T extends [infer F, ...infer R] ? [F extends object ? Camelize<F> : F, ...CamelizeArray<R>] : []; //数组
type Camelize<T extends object> = T extends any[] ? CamelizeArray<T> :
{ [P in keyof T as P extends string ? CamelizeOne<P> : P]: T[P] extends object ? Camelize<T[P]> : T[P] };
// old way
// /**驼峰命名 */
// type CamelizeKey<T extends string> = T extends `${infer L}_${infer RF}${infer R}` ? `${L}${Uppercase<RF>}${CamelizeKey<R>}` : T;
// type Camelize<T extends object> = T extends any[] ?
// { [P in keyof T]: P extends `${number}`/*only index elements*/ ? (T[P] extends object ? Camelize<T[P]> : T[P]) : T[P] } : //数组
// { [P in keyof T as P extends string ? CamelizeKey<P> : P]: T[P] extends object ? Camelize<T[P]> : T[P] }; //结构体
Solution by E-uler #24962
type SnakeToCamelCase<S extends string> = S extends `${infer SFirst}_${infer SRest}`
? `${Lowercase<SFirst>}${SnakeToCamelCase.Rest<SRest>}` : Lowercase<S>
namespace SnakeToCamelCase {
export type Rest<S extends string> = S extends `${infer SCurrent}_${infer SRest}`
? `${Capitalize<SCurrent>}${Rest<SRest>}` : Capitalize<S>
}
type Camelize<T> = T extends unknown[] ? Camelize.FromArray<T> : (
T extends Record<string, unknown> ? Camelize.FromObject<T> : T
)
namespace Camelize {
export type FromObject<T extends Record<string, unknown>> = {
[Key in keyof T as Key extends string ? SnakeToCamelCase<Key> : Key]: Camelize<T[Key]>
} & {}
export type FromArray<T extends unknown[]> = T extends [infer T0, ...infer TRest] ? (
[Camelize<T0>, ...FromArray<TRest>]
) : T extends [] ? [] : Camelize<T[number]>[]
}
Solution by BOCbMOU #24851
type CamelCase<S extends string> = S extends `${infer First}_${infer Rest}`
? `${First}${CamelCase<Capitalize<Rest>>}`
: S
type CamelizeArray<T> = T extends [infer F, ...infer Rest]
? [Camelize<F>, ...CamelizeArray<Rest>]
: []
type Camelize<T> = {
[Key in keyof T as Key extends string ? CamelCase<Key> : never ]: T[Key] extends any[]
? CamelizeArray<T[Key]>
: T[Key] extends object
? Camelize<T[Key]>
: T[Key]
}
Solution by NeylonR #24450
// your answers
type CamelCase<S extends string> = S extends `${infer F}_${infer M}${infer E}` ?
`${Lowercase<F>}${Uppercase<M>}${CamelCase<E>}` : Lowercase<S>;
type CamelizeArray<T> = T extends [infer F, ...infer Rest] ? [Camelize<F>, ...CamelizeArray<Rest>] : [];
type Camelize<T> = {
[key in keyof T as key extends string ? CamelCase<key>: never]: T[key] extends any[] ?
CamelizeArray<T[key] > : T[key] extends object ? Camelize<T[key]> : T[key]
}
Solution by snakeUni #23836
type IsTuple<T> = T extends any[] ? (number extends T['length'] ? false : true) : false
type CamelizeTuple<T> = T extends [infer F, ...infer R]
? R['length'] extends 0
? [Camelize<F>]
: [Camelize<F>, ...CamelizeTuple<R>]
: [T]
type Camelize<T> = IsTuple<T> extends true
? CamelizeTuple<T>
: T extends object
? {
[K in keyof T as K extends `${infer F}_${infer R}`
? `${F}${Capitalize<R>}`
: K]: T[K] extends object ? Camelize<T[K]> : T[K]
}
: T
Solution by TKBnice #23319
type CamelCase<S extends string> = S extends `${infer F}_${infer M}${infer E}` ?
`${Lowercase<F>}${Uppercase<M>}${CamelCase<E>}` : Lowercase<S>;
type CamelizeArray<T> = T extends [infer F, ...infer Rest] ? [Camelize<F>, ...CamelizeArray<Rest>] : [];
type Camelize<T> = {
[key in keyof T as key extends string ? CamelCase<key>: never]: T[key] extends any[] ?
CamelizeArray<T[key] > : T[key] extends object ? Camelize<T[key]> : T[key]
}
Solution by Karamuto #22037
type STOC<S extends string> = S extends `${infer A}_${infer B}` ? `${A}${Capitalize<STOC<B>>}` : S
type Camelize<T> = T extends any[]
? T extends [infer A, ... infer B] ? [Camelize<A>, ...Camelize<B>] : []
: {
[K in keyof T as K extends string ? STOC<K> : never]:
T[K] extends { [_: keyof any]: any } ? Camelize<T[K]> : T[K]
}
Solution by goddnsgit #21913
type CamelizeString<T extends PropertyKey> = T extends `${infer First}_${infer Last}`
? `${First}${CamelizeString<Capitalize<Last>>}`
: T;
type Camelize<T> = T extends any[]
? { [K in keyof T]: Camelize<T[K]> }
: T extends Record<PropertyKey, any>
? {
[K in keyof T as CamelizeString<K>]: Camelize<T[K]>;
}
: T;
type T1 = Camelize<{
some_prop_prop2__a: string;
prop: { another_prop: string };
array: [{ snake_case: string; snake_b: number }];
}>;
Solution by zqiangxu #21826
type CamelizeString<S extends string> =
S extends `${infer Head}${infer Rest}`
? Head extends '_'
? CamelizeString<Capitalize<Rest>>
: `${Head}${CamelizeString<Rest>}`
: S
type Camelize<T> =
T extends unknown[]
? T extends [infer First, ...infer Rest]
? [Camelize<First>, ...Camelize<Rest>]
: []
: T extends object
? {
[P in keyof T as (P extends string ? CamelizeString<P> : P)]: Camelize<T[P]>
}
: T
Solution by zhaoyao91 #21348
// your answers
type ToCamelize<S> = S extends `${infer F}_${infer R}` ?
`${F}${Capitalize<R>}` extends `${infer F1}_${infer R1}` ?
ToCamelize<`${F1}_${R1}`> : `${F}${Capitalize<R>}` : S
type Camelize<T> = {
[K in keyof T as ToCamelize<K>] : T[K] extends any[] ? ProcessArr<T[K]> : T[K] extends object ? Camelize<T[K]> : T[K]
}
type ProcessArr<A,N = []> = A extends [infer F,...infer R] ? F extends object ? N extends [...infer Rest] ? ProcessArr<R,[...Rest,Camelize<F>]> : N : N : N
Solution by YqxLzx #21317
type StringToUnion<S> = S extends `${infer F}${infer R}`
? F | StringToUnion<R>
: S;
type CapitalizeCamelCase<
S extends string,
R extends string = ""
> = S extends `${infer A}_${infer B}`
? CapitalizeCamelCase<B, `${R}${Capitalize<A>}`>
: `${R}${Capitalize<S>}`;
type CamelCase<S extends string> = "_" extends StringToUnion<S>
? Uncapitalize<CapitalizeCamelCase<Lowercase<S>>>
: Lowercase<S>;
type ArrCamelizeDeep<T, Result extends Array<any> = []> = T extends [
infer A,
...infer B
]
? ArrCamelizeDeep<B, [...Result, Camelize<A>]>
: Result;
type Camelize<T> = {
[P in keyof T as P extends string ? CamelCase<P> : P]: T[P] extends Array<any>
? ArrCamelizeDeep<T[P]>
: T[P] extends Record<string, any>
? Camelize<T[P]>
: T[P];
};
Solution by so11y #21234
// your answers
type _CamelizeKey<P> = P extends `${infer F}_${infer C}${infer Rest}`
? `${F}${Uppercase<C>}${_CamelizeKey<Rest>}`
: P;
type Camelize<T> = T extends Record<string, unknown>
? { [P in keyof T as _CamelizeKey<P>]: Camelize<T[P]> }
: T extends [infer F, ...infer Rest]
? [Camelize<F>, ...Camelize<Rest>]
: T;
Solution by fengjinlong #20260
type _CamelizeHelp<P> =
P extends `${ infer F }_${ infer C }${ infer Rest }`
? `${ F }${ Uppercase<C> }${ _CamelizeHelp<Rest> }`
: P
type Camelize<T> =
T extends Record<string, unknown>
? { [P in keyof T as _CamelizeHelp<P>]: Camelize<T[P]> }
: T extends [infer F, ...infer Rest]
? [Camelize<F>, ...Camelize<Rest>]
: T
Solution by lvjiaxuan #20036
type CamelizeSingleWord<S extends string, Total extends string = ''> = S extends `${infer F}_${infer R}`
? CamelizeSingleWord<R, `${Total}${'' extends Total ? F : Capitalize<F>}`>
: '' extends Total
? S
: `${Total}${Capitalize<S>}`;
type Camelize<T> = T extends unknown[]
? T extends [infer F, ...infer R]
? [Camelize<F>, ...Camelize<R>]
: []
: { [p in keyof T as p extends string ? CamelizeSingleWord<p> : never]: T[p] extends object ? Camelize<T[p]> : T[p] };
Solution by CaoXueLiang #19261
// your answers
type CamelizeKey<K> = K extends `${infer F}_${infer R}`
? `${F}${CamelizeKey<Capitalize<R>>}`
: K
type Camelize<T> = T extends unknown[]
? T extends [infer F, ...infer R]
? [Camelize<F>, ...Camelize<R>]
: []
: {
[P in keyof T as CamelizeKey<P>]: T[P] extends object
? Camelize<T[P]>
: T[P]
}
Solution by humandetail #16482
// your answers
type Cm<
S extends string> =
S extends `${infer R extends string}_${infer U extends string}`
?`${Capitalize<Lowercase<R>>}${Cm<U>}`
: Capitalize<Lowercase<S>> ;
type CamelCase<
S> =
S extends string
? Uncapitalize<Cm<S>>
: S ;
type Camelize<T> =
T extends readonly any[]
? T extends [infer R,...infer U]
? [Camelize<R>,...Camelize<U>]
: []
: T extends object
? {[J in keyof T as CamelCase<J>] : Camelize<T[J]>}
: T ;
Solution by justBadProgrammer #15909