Skip to content

Instantly share code, notes, and snippets.

@eliasfeijo
Last active June 24, 2022 07:54
Show Gist options
  • Save eliasfeijo/672c83ff971653b551e168b156bb3baf to your computer and use it in GitHub Desktop.
Save eliasfeijo/672c83ff971653b551e168b156bb3baf to your computer and use it in GitHub Desktop.
Typescript function to replace an object's symbol keys with equivalent string keys
// Javascript version: https://gist.github.com/eliasfeijo/0b1286a88faef97e752dcb72f925cbee
type TDefaultRecord = Record<string | number | symbol, unknown>;
type TDefaultRecordOrArray = TDefaultRecord | Array<unknown>;
type TRecordWithStringKeys = Record<string, unknown>;
type TaskPerformResponse = TRecordWithStringKeys | Array<unknown> | unknown;
type TaskRunResponse = TRecordWithStringKeys;
class SymbolKeysToStringTask {
private symbolCounter = 0;
private perform(o: TDefaultRecordOrArray): TaskPerformResponse {
const isArray = o.constructor === Array;
const newObject: TDefaultRecordOrArray = isArray ? o : {};
Reflect.ownKeys(o).forEach(key => {
// if (isArray === true && key is NaN) means that it is an internal property of array e.g., "length", we won't collect those
if (isArray && isNaN(Number(key))) return;
const value = isArray ? o[Number(key)] : o[key as any];
let parsedKey = key;
if (typeof key === 'symbol') {
if (key.description) parsedKey = key.description;
else {
parsedKey = `_symbol${++this.symbolCounter}`;
}
}
if (value !== null && typeof value === 'object') {
newObject[parsedKey as any] = this.perform(value as TDefaultRecordOrArray);
return;
}
newObject[parsedKey as any] = value;
});
return newObject;
}
public static run(o: TDefaultRecord): TaskRunResponse {
const task = new SymbolKeysToStringTask();
return task.perform(o) as TaskRunResponse;
}
}
// Usage:
const myObject = {
// Accepts numeric keys
1: 'some value',
// Accepts string keys
stringKey: 'another value',
// Using Symbol.for(keyName)
[Symbol.for('KEY_A')]: 'A',
// Using Symbol(keyName)
[Symbol('KEY_B')]: 'B',
// Using Symbol()
[Symbol()]: 1,
[Symbol()]: 2,
// Using Symbol() with nested objects and arrays
[Symbol()]: {
[Symbol()]: 'inside nested object',
[Symbol()]: [
{ [Symbol()]: 'inside nested array' }
],
},
}
const newObject = SymbolKeysToStringTask.run(myObject);
console.log(newObject);
/* Output
* {
* "1": "some value",
* "stringKey": "another value",
* "KEY_A": "A",
* "KEY_B": "B",
* "_symbol1": 1,
* "_symbol2": 2,
* "_symbol3": {
* "_symbol4": "inside nested object",
* "_symbol5": [
* {
* "_symbol6": "inside nested array"
* }
* ]
* }
* }
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment