0

I want to convert my typescript object keys to upper case, I want to know a good way to turn this?

var obj = {key1: value1,key2: value2}; into:

var obj = {KEY1: value1,KEY2: value2};

Can anyone suggest a better method without multiple looping and all?

Athulya Ratheesh
  • 291
  • 4
  • 22
  • Does this answer your question? [What's the best way (most efficient) to turn all the keys of an object to lower case?](https://stackoverflow.com/questions/12539574/whats-the-best-way-most-efficient-to-turn-all-the-keys-of-an-object-to-lower) – Tobias S. Apr 11 '22 at 08:42
  • 1
    That's obviously the Javascript solution - I'm curious if OP was looking to maintain typesafety while doing so – Dane Brouwer Apr 11 '22 at 08:42

3 Answers3

0
x = {}
Object.entries(obj).forEach(([k, v]) => {x[k.toUpperCase()] = v})
obj = x
David Sainez
  • 6,446
  • 1
  • 22
  • 45
  • 1
    This will still not have impact on types, because key signature of `x` still wil be a plain `string`. – tymzap Apr 12 '22 at 11:59
0

The most complicated part of this would be the typesafety as the Javascript is pretty straight forward.

All we need to do is isolate the keys/types we need to build out the "uppercased" copy of the object.

// All string-type keys in the object, and then uppercased
type UppercaseStringKeys<T> = Uppercase<Extract<keyof T, string>>;
// All non-string-type keys in the object type T
type NonStringKeys<T> = Exclude<keyof T, string>;
// Union of the above types
type NonStringAndUppercaseStringKeys<T> = NonStringKeys<T> | UppercaseStringKeys<T>;
// An object consisting of the above keys with the same values from the original object
type UppercaseObjectKeys<T extends { [key: string | number | symbol]: any }> = {
    [x in UppercaseStringKeys<T>]: x extends string ? T[Lowercase<x>] : T[x];
};

We can obviously make this shorter - the above is purely for readability

type UppercaseObjectKeys<T extends { [key: string | number | symbol]: any }> = {
    [x in Uppercase<Extract<keyof T, string>> |  Exclude<keyof T, string>]: x extends string ? T[Lowercase<x>] : T[x];
};

Now all we need to do is do the Typescript mapping.

function uppercaseObjectKeys<T extends Record<any, any>>(existingObject: T) {
    return Object.keys(existingObject).reduce((acc,key) => {
        const newKey = `${key}`.toUpperCase() as keyof UppercaseObjectKeys<T>;
        acc[newKey] = existingObject[key];
        return acc;
    }, {} as UppercaseObjectKeys<T>);
}

That's also fairly straight forward, we just return a new object with the "uppercased" keys.

We could edit the original object, but that's not the crux of this questions.

Then using the above function is straight forward, it should return us the new object with all string-type keys uppercased.

const x = {
  foo: {},
  bar: 1,
  bazz_bazz: 'some string',
  1: 2,
};
const y = uppercaseObjectKeys(x);
console.log(x);
/** {
  "1": 2,
  "foo": {},
  "bar": 1,
  "bazz_bazz": "some string"
} */
console.log(y);
/** {
  "1": 2,
  "FOO": {},
  "BAR": 1,
  "BAZZ_BAZZ": "some string"
} */
// works
y[1];
// wont work
y[2];
Dane Brouwer
  • 2,827
  • 1
  • 22
  • 30
  • Excellent approach, what if I need to set uppercase on the values not the keys? I need to set to uppercase all type==="string" values in the object. – Francisco Souza Oct 06 '22 at 12:45
  • 1
    We would have to adjust `UppercaseObjectKeys` slightly - there are a number of questions I would have to ask though. So it would probably be better off as a separate question. – Dane Brouwer Oct 06 '22 at 14:03
0

Assuming you have:

const obj1 = { key1: '', key2: '' };

You can do:

import { ValueOf } from "type-fest";

const uppercasedObj1 = Object.fromEntries(
  Object.entries(obj1).map(
    ([value, key]) => [value.toUpperCase(), key]
  )
) as Record<Uppercase<keyof typeof obj1>, ValueOf<typeof obj1>>;

Explanation: Some kind of looping is needed, you can't avoid this. In this case we used Object.entries() and Object.fromEntries() to declaratively loop through object properties - not the most optimal way, but quite declarative and relatively easy to write.

As for make it work for TypeScript, we need to cast the type after looping, because index signature of looped object would be always string. Here we used built-in Uppercase type to transform keys and ValueOf from TypeFest library (just to not litter the example with typing value of object).

tymzap
  • 896
  • 7
  • 10