Intrinsic string types by ahejlsberg · Pull Request #40580 · microsoft/TypeScript (original) (raw)
Think we can add something like Camelize
or SnakeCase
to convert from snake_case
to camelCase
etc? It would be cool if we could define our own somehow.
Would be really sweet if we could finally type a recursive camelize function.
This does it for a fixed word length:
type B = 'hi_mate';
type Camelize = S extends ${infer A}_${infer B}
? ${A}${Capitalize<B>}
: unknown;
type C = Camelize;
Is there a way to use spread to do it for many?
Have managed to do it like this but it's hideous:
type Z = 'hi_mate_what_up_good_morning_today';
type Camelize< S
= S extends
${infer A}_${infer B}_${infer C}_${infer D}_${infer E}_${infer F}_${infer G}_${infer H}
?${A}${Capitalize<B>}${Capitalize<C>}${Capitalize<D>}${Capitalize<E>}${Capitalize<F>}${Capitalize<G>}${Capitalize<H>}
: S extends${infer A}_${infer B}_${infer C}_${infer D}_${infer E}_${infer F}_${infer G}
?${A}${Capitalize<B>}${Capitalize<C>}${Capitalize<D>}${Capitalize<E>}${Capitalize<F>}${Capitalize<G>}
: S extends${infer A}_${infer B}_${infer C}_${infer D}_${infer E}_${infer F}
?${A}${Capitalize<B>}${Capitalize<C>}${Capitalize<D>}${Capitalize<E>}${Capitalize<F>}
: S extends${infer A}_${infer B}_${infer C}_${infer D}_${infer E}
?${A}${Capitalize<B>}${Capitalize<C>}${Capitalize<D>}${Capitalize<E>}
: S extends${infer A}_${infer B}_${infer C}_${infer D}
?${A}${Capitalize<B>}${Capitalize<C>}${Capitalize<D>}
: S extends${infer A}_${infer B}_${infer C}
?${A}${Capitalize<B>}${Capitalize<C>}
: S extends${infer A}_${infer B}
?${A}${Capitalize<B>}
: S;
type C = Camelize; // hiMateWhatUpGoodMorningToday
function upperFirst(s: S) {
const [head, ...tail] = s;
return [head.toUpperCase(), ...tail].join('') as Capitalize;
}
const z = upperFirst('hello');
function camelCase(s: S) {
const [head, ...tail] = s.split('_');
return ${head}${tail.map(upperFirst).join('')}
as Camelize;
}
const y = camelCase('hello_mate');
So far so good, now I just have to figure out a way of doing the typing recursively on an object.
Ok, I think I nailed it:
type DeepCamelize = { [K in keyof T as Camelize]: DeepCamelize<T[K]>; };
Would still be nice to get: Same in reverse, and maybe an implementation that uses spread.
Ok, improved version usingJoin
and a modified splitter:
type CapitalizeIf< Condition extends boolean, T extends string
= Condition extends true ? Capitalize : T;
type SplitCamel< S extends string, D extends string, IsTail extends boolean = false
= string extends S ? string[] : S extends '' ? [] : S extends
${infer T}${D}${infer U}
? [CapitalizeIf<IsTail, T>, ...SplitCamel<U, D, true>] : [CapitalizeIf<IsTail, S>];
type Camelize = S extends string ? Join<SplitCamel<S, '_'>, ''> : S;
type DeepCamelize = { [K in keyof T as Camelize]: DeepCamelize<T[K]>; };