I want to know if it is possible to type this function. I am recursively checking for a type of value inside an object (shouldReplace
is a type guard), and passing that value to the function fn
const replaceInObject = (shouldReplace, fn) => {
const recurse = object => {
for (const [key, val] of Object.entries(object)) {
if (shouldReplace(val)) object[key] = fn(val)
else if (Array.isArray(object)) object[key] = val.map(recurse)
else if (typeof object === 'object') object[key] = recurse(val)
}
}
return recurse
}
For clarity, here is an example usage:
const isEs6Map = (val: any): val is Map<any, any> => val instanceof Map
const es6MapToObject = <K, V>(map: Map<K, V>): { [key: string]: V } => {
const obj: { [key: string]: V } = {}
for (const [key, val] of map) obj[key.toString()] = val
return obj
}
const marshal = replaceInObject(isEs6Map, es6MapToObject)
const sampleInput = {
m: new Map([['a', 1], ['b', 2]]),
meta: 'info',
children: [
{
m: new Map([['c', 3], ['d', 4]]),
meta: 'child'
}
]
}
const serializedData = marshal(sampleInput)
The use case is essentially creating a generic marshalling function. I have objects stored in memory using Maps, and I want to send these across the network so that they can be viewed in a web ui. I need to convert all the classes into pure data objects so that they can be properly serialized by JSON.stringify
.
If it is not possible to type this function, I can of course, accomplish the same task with several serializer function & types specific to each input object. I am hoping however that it is possible to avoid writing types whos output can be described with this simple function.
This stackoverflow question is related, but does not deal with recursion, or choosing which values to replace. Typescript: Generic object mapping function