Home > OS >  Cast object nested properties to new type
Cast object nested properties to new type

Time:09-28

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.

  • Related