A handy utility type called Uppercase<T> is available in TypeScript for manipulating strings. It takes a string literal as input and outputs the uppercase version of that string. For example, Uppercase<"abc">
results in "ABC"
, both being of the same type. By leveraging this utility type, we can create a mapped type with remapped keys to define the output of the toEnum()
function based on the union of its argument's string literals:
function toEnum<K extends string>(...strings: K[]): { [P in K as Uppercase<P>]: P } {
const enumObject: any = {};
strings.forEach((str) => {
enumObject[str.toUpperCase()] = str;
});
return enumObject;
}
It's important to note that toEnum()
is generic in K
, ensuring that strings
is an array of strings. This constraint aids in inferring string literal types for the elements rather than just generic strings. The type
{[P in K as Uppercase<P>]: P}
maps each string
P
in the original union
K
to its uppercase counterpart as the key and retains the same
P
as the value.
For customization requirements like converting lower camel case strings to SCREAMING_SNAKE_CASE, TypeScript offers advanced features such as template literal types and recursive conditional types. An operation like this can be achieved using a combination of these features at both the type and value levels:
type LowerPascalToUpperSnake<T extends string, A extends string = ""> =
T extends `${infer F}${infer R}` ? LowerPascalToUpperSnake<R,
`${A}${F extends Lowercase<F> ? "" : "_"}${Uppercase<F>}`
> : A;
function lowerPascalToUpperSnake<T extends string>(str: T) {
return str.split("").map(
c => (c === c.toLowerCase() ? "" : "_") + c.toUpperCase()
).join("") as LowerPascalToUpperSnake<T>
}
This allows for transforming strings from lower Pascal case to upper snake case format. By integrating this transformation into the toEnum()
function instead of the default uppercase conversion, unique casing requirements can be met effectively:
function toEnum<K extends string>(...strings: K[]):
{ [P in K as LowerPascalToUpperSnake<P>]: P } {
const enumObject: any = {};
strings.forEach((str) => {
enumObject[lowerPascalToUpperSnake(str)] = str;
});
return enumObject;
}
Testing this updated functionality showcases successful mappings from lower Pascal case inputs to upper snake case outputs:
const myEnum = toEnum('one', 'two', 'three', "fortyFive");
/* const myEnum: {
ONE: "one";
TWO: "two";
THREE: "three";
FORTY_FIVE: "fortyFive";
} */
console.log(myEnum.FORTY_FIVE) // "fortyFive"
By embracing the flexibility of TypeScript's template literal types, complex string transformations can be efficiently implemented within your codebase.