Based on the answer in this post Typescript how to map type keys to camelCase I've added types for a camelize
function to transform snake case objects to camel case with typing.
It works for the most part, but I'm struggling with the arrays. I'd like the type of the array properties to stay arrays, and the items of the array to keep their types, but I'm having a hard time figuring out how to declare the types properly.
This is the code for the types and the camelize function themselves:
import { types } from 'util'
import { camelCase } from 'lodash'
type CamelCase<S extends string> = S extends `${infer P1}_${infer P2}${infer P3}`
? `${Lowercase<P1>}${Uppercase<P2>}${CamelCase<P3>}`
: Lowercase<S>
type KeysToCamelCase<T> = {
[K in keyof T as CamelCase<string &K>]: T[K] extends {} ? KeysToCamelCase<T[K]> : T[K]
}
function walk(obj): any {
if (!obj || typeof obj !== 'object') return obj
if (types.isDate(obj) || types.isRegExp(obj)) return obj
if (Array.isArray(obj)) return obj
return Object.keys(obj).reduce((res, key) => {
const camel = camelCase(key)
res[camel] = walk(obj[key])
return res
}, {})
}
export default function camelize<T>(obj: T): T extends String ? string : KeysToCamelCase<T> {
return (typeof obj === 'string' ? camelCase(obj) : walk(obj))
}
The conversion itself works well and for simple types the keys are transformed correctly and the type of the value stays in place, but the array properties are not like I want them. The example below won't work, because the roles
and nestedArray
properties are no longer have the string[] type.
function wantCamel(obj: {
id: number,
firstName: string;
roles: string[],
nested: {
nestedArray: string[]
}
}) {
return obj
}
wantCamel(camelize<{
id: number;
first_name: string;
roles: string[],
nested: {
nested_array: string[],
}
}>({
id: 123,
first_name: 'John Doe',
roles: ['user', 'admin'],
nested: {
nested_array: ['one', 'two']
}
}))
...i get the following error, which i interpret as the value no longer being an array and therefore conflicting with the expected string[] type:
Argument of type 'KeysToCamelCase<{ id: number; first_name: string; roles: string[]; nested: { nested_array: string[]; }; }>' is not assignable to parameter of type '{ id: number; firstName: string; roles: string[]; nested: { nestedArray: string[]; }; }'.
Types of property 'roles' are incompatible.
Type 'KeysToCamelCase<string[]>' is missing the following properties from type 'string[]': indexOf, lastIndexOf, forEach, reduceRight, and 5 more.ts(2345)
I've tried a few different things (overloading declarations, expanding KeysToCamelCase type etc., but to no avail.
question from:
https://stackoverflow.com/questions/65865302/creating-a-camelize-function-for-nested-objects-with-typing