Home > Mobile >  Is there a way to assign an object leveling equally the nested objects of the source?
Is there a way to assign an object leveling equally the nested objects of the source?

Time:02-02

I'm using interfaces to automate some tests, storing the required params to do some action, like the following for example:

interface AdmissionFormParams {
  companyParams: {
    // some company data
  }
  employeeParams: {
    name: string
    id: number
    optionalParams?: {
      email: string
      phone: string
    }
  }
}

So I have a file to store all the data used along the tests (using the example for above would be like this):

Complete registry:

const admissionDataAllParams: AdmissionFormParams = {
  companyParams: {
    // some company data
  },
  employeeParams: {
    name: 'Manolo',
    id: 5432,
    optionalParams: {
      email: '[email protected]',
      phone: '99999999'
    }
  }
}

Incomplete Registry:

const admissionDataRequiredParams: AdmissionFormParams = {
  companyParams: {
    // some company data
  },
  employeeParams: {
    name: 'John',
    id: 2425
  }
}

This two are being used to complete the Create scenario.

After the register successfully succeed, the Employee's data will be visible at one tab of the registry, while the Company's data in another.

I have to assert both of them, and for this im using a new interface ommiting the optionalParams and making them all required, cause the assertion will be done in both cases (empty or filled fields):

interface EmployeeDataParams {
  name: string
  id: number
  email: string
  phone: string
}

How can I create an object assigning the data of admissionData.employeeParams but using it's optionalParams on the same level to all of them (all required)?

I was using as the follow, but the file is getting tooo extensive (used some small examples here).

Incomplete registry:

const employeeDataRequiredParams: EmployeeDataParams = {
  name: admissionDataRequiredParams.employeeParams.name,
  id: admissionDataRequiredParams.employeeParams.id,
  email: '',
  phone: ''
}

Complete registry:

const employeeDataAllParams: EmployeeDataParams = {
  name: admissionDataAllParams.employeeParams.name,
  id: admissionDataAllParams.employeeParams.id,
    email: admissionDataAllParams.employeeParams.optionalParams?.email ?? "",
    phone: admissionDataAllParams.employeeParams.optionalParams?.phone ?? ""
}

CodePudding user response:

Given your example code, I think the least repetitive approach would be to use destructuring assignment to copy the employeeParams object into two variables, and then spread those variables back into a new object literal. For example:

function toDataParams(x: AdmissionFormParams): EmployeeDataParams {
    const { optionalParams = { email: "", phone: "" }, ...employeeParams } =
        x.employeeParams;
    return { ...optionalParams, ...employeeParams };
}

In the first line, we destructure x.employeeParams into a optionalParams variable (which, if absent in x.employeeParams, becomes a default value {email: "", phone: ""}) and then put the rest of the properties into an employeeParams variable.

So optionalParams is therefore of type {email: string; phone: string}, and employeeParams is of type {name: string; id: number} (and does not contain an optionalParams property). Then we just spread those together into the return value, which is necessarily of type EmployeeDataParams.


It's possible that depending on your actual use case there are other approaches which turn out to use less code, but given the example as written this is fairly minimal. If you don't care about the returned value possibly having an unused optionalParams property, you can get even terser this way:

function toDataParams(x: AdmissionFormParams): EmployeeDataParams {
    return {
        ...x.employeeParams.optionalParams ?? { email: "", phone: "" },
        ...x.employeeParams
    };
}

Playground link to code

  • Related