I previously made a general purpose function that recursively cast nested property values into number:
type CastToNumber<T> = T extends string ? number : {
[K in keyof T]: CastToNumber<T[K]>
};
type StringMap = { [key: string]: any };
const castObjectValuesToNumber = function<T extends StringMap, K extends keyof T>(initialObj: T, nestedProp?: string): CastToNumber<T> {
let _castedObj: StringMap = {};
for(const [property, value] of Object.entries(initialObj)) {
if(typeof(value) === "object") {
const newVal = castObjectValuesToNumber(value, property) as CastToNumber<T>;
_castedObj = { ..._castedObj, ...newVal };
} else {
if(nestedProp) {
if(!_castedObj[nestedProp]) _castedObj[nestedProp] = {};
_castedObj[nestedProp][property] = value;
} else {
_castedObj[property] = value;
}
}
}
return _castedObj as CastToNumber<T[K]>;
}
This was working well for most objects but I recently had to cast this object and it didn't work.
const army = {
cavalry: {
light: { quantity: "0", health: "0" },
heavy: { quantity: "0", health: "0" }
},
infantry: {
light: { quantity: "0", health: "0" },
heavy: { quantity: "0", health: "0" }
},
magic: {
light: { quantity: "0", health: "0" },
heavy: { quantity: "30", health: "0" }
},
range: {
light: { quantity: "0", health: "0" },
heavy: { quantity: "0", health: "0" }
}
};
const result = castObjectValuesToNumber(army);
/*
result = {
light: { quantity: 0, health: 0 },
heavy: { quantity: 0, health: 0 }
};
wanted = {
cavalry: {
light: { quantity: 0, health: 0 },
heavy: { quantity: 0, health: 0 }
},
infantry: {
light: { quantity: 0, health: 0 },
heavy: { quantity: 0, health: 0 }
},
magic: {
light: { quantity: 0, health: 0 },
heavy: { quantity: 30, health: 0 }
},
range: {
light: { quantity: 0, health: 0 },
heavy: { quantity: 0, health: 0 }
}
}
*/
It is only returning a limited scope of nested properties, because it doesn't properly store properties and recursively set them. I can't find a way to make this function work for deeply nested properties.
CodePudding user response:
_castedObj = { ..._castedObj, ...newVal };
should be
_castedObj[property] = newVal;
CodePudding user response:
it is a simple recursive function to iterate an object.
const army = {cavalry:{light:{quantity:"0",health:"0"},heavy:{quantity:"0",health:"0"}},infantry:{light:{quantity:"0",health:"0"},heavy:{quantity:"0",health:"0"}},magic:{light:{quantity:"0",health:"0"},heavy:{quantity:"30",health:"0"}},range:{light:{quantity:"0",health:"0"},heavy:{quantity:"0",health:"0"}}};
function iterate(obj) {
Object.keys(obj).forEach(function(key) {
var value = obj[key];
if (typeof value === 'object' && value != null) {
iterate(value)
}
if (typeof value === "string") {
obj[key] = value;
}
})
}
iterate(army)
console.log(army)
.as-console-wrapper {max-height: 100% !important}
CodePudding user response:
Here's a simple version, which recursively maps a function over an object/array/other structure:
const deepMap = (fn) => (o) =>
Array .isArray (o)
? o .map (deepMap (fn))
: Object (o) === o
? Object .fromEntries (Object .entries (o) .map (([k, v]) => [k, deepMap (fn) (v)]))
: fn (o)
const army = {cavalry: {light: {quantity: "0", health: "0"}, heavy: {quantity: "0", health: "0"}}, infantry: {light: {quantity: "0", health: "0"}, heavy: {quantity: "0", health: "0"}}, magic: {light: {quantity: "0", health: "0"}, heavy: {quantity: "30", health: "0"}}, range: {light: {quantity: "0", health: "0"}, heavy: {quantity: "0", health: "0"}}}
console .log (deepMap (Number) (army))
.as-console-wrapper {max-height: 100% !important; top: 0}
Here we call it with the Number
constructor, but we could map using anything.