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
};
}