Home > Blockchain >  Typescript - object projection
Typescript - object projection

Time:10-23

Give an arbitrary array of objects and an array of paths as strings in "dot notation" format is there a way to project to a new object?

For example given an array people and a list of paths (dot notation):

const people = [
  {
    firstName: 'John',
    lastName: 'Doe',
    address: {
      city: 'New York',
      country: 'US'
    }
  },
  {
    firstName: 'Sally',
    lastName: 'Jane',
    address: {
      city: 'Londaon',
      country: 'UK'
    }
  }
] as Person[]

const paths = ['firstName','address.country'];

Is there a way using Array.map(p => ???) to dynamically project with just the provided paths? The result for the above would end up being:

[
  {
    firstName: 'John',
    address: {
      country: 'US'
    }
  },
  {
    firstName: 'Sally',
    address: {
      country: 'UK'
    }
  }
]

My end goal is to take an array of objects and serialize using JSON.stringify(people) using the selected paths.

CodePudding user response:

You could recursively follow the paths and then always pass along the object of at the last path. E.g:

function followPath(obj: any, pathParts: string[]): any {
  const result: { [k: string]: any } = {};

  const firstPath = pathParts.shift();
  if (firstPath === undefined) {
    return {};
  }

  if (pathParts.length > 0) {
    result[firstPath] = followPath(obj[firstPath], pathParts);
  } else {
    result[firstPath] = obj[firstPath];
  }

  return result;
}


const paths = ['firstName', 'address.country'];

const newArray = oldArray.map((v) => {
  const newObject = {};

  for (const path of paths) {
    const parts = path.split('.');
    const firstPath = parts.shift();
    if (firstPath === undefined) {
      continue;
    }
    
    newObject[firstPath] = parts.length > 0
      ? followPath(v[firstPath], parts)
      : v[firstPath];
  }

  return newObject;
});
  • Related