How To Camelize Object Typing in TypeScript Without Any Library
Around version 4.1 of TypeScript, it introduces support for the Template Literal String Types. And so if you’d like to try this, you would have to make sure you are on the 4.1 or above version of TypeScript.
Often times in our development, we have to integrate our frontend apps to a backend that is based on a different naming convention when returning a response to consume.
For example, on one of our projects we have a NextJS app and a Python/Django backend. The convention on Python/Django is in snake_case format and so the JSON response for it is in snake_case.
You get the idea… the response from the backend is in snake_case and we have to consume the response, but we have to convert it first to camelCase.
How did we handle that one?
Converting the object from snake_case to camelCase is fairly easy. We use the library humps to convert it (the object itself, not the object typing).
GitHub - domchristie/humps: 🐫 Underscore-to-camelCase converter (and vice versa) for strings and…
But the TypeScript typing is a little harder. Well, especially before when there’s no support for Template Literal String Types.
Here’s the typing which I’m going to try to explain what’s happening:
🕵️ Time To Probe
Let us now try to understand what’s happening.
- CamelizeString is a custom type that “accepts” a string. That’s how we can read the
<ObjectProperty extends string>part. If the passed generic type isn’t a string, then it will throw an error.
- Once we are able to pass a type string, it then checks if the string is in snake_case and returns as is if not in snake_case.
- Using Template Literal String Types we were able to conditionally check if the passed type is on snake_case and convert it otherwise, return as is.
- Camelize is a custom type that “accepts” a generic type object. Unlike CamelizeString, this custom type accepts any object.
- On line 2, what we are doing is “loop” into the passed generic type object, grab each property and assign it to “ObjectProperty”. And then lastly, convert or force cast “ObjectProperty” to a CamelizeString. This would essentially convert the object key from snake_case to camelCase.
- As we are looping on each property with the passed generic type object, we then check if the generic type object property value is an array or an object.
- It is basically doing something if
obj[prop]is an Array, check if the item in the Array is an object. If it is an object, iterate and camelize each property, otherwise, return it as is. You can think of it as a nested transformation. The nested ternary isn’t beautiful and hard to understand but hopefully the tabbing allows you to see the respective flow.
🚀 Bringing It All Together
At the time of writing this, there seems to be supported now
@types/humps which would automatically convert it now to you when you used the library and install the typings.
So I would suggest using that instead of doing it manually on your own. That’s probably much more type-safety in case I missed some edge case.
If you are interested in exploring it more, here’s a full demo using TypeScript Playground! 🚀
Hope you learned something new today.
As always, if you have some new ideas on how to improve them, feel free to shoot a comment.
Documentation - Template Literal Types
Template literal types build on string literal types, and have the ability to expand into many strings via unions. They…