'How to recursively check property types in an object
I'm writing a function that takes in an object (A), compares it with another object (B) and creates a new object (C). Both A and B objects are symmetrical (same amount of properties, same keys) but the type of their values can differ. Eg: A.amount can be '11' while B.amount is a number. The end result should be an object C that has the values from A with the types from B.
In the function I came up with, I'm looping through all properties in object A, checking the type of the properties in object B with a switch/case statement, applying type conversion (like .toString()
) and adding the corrected property to object C.
I would like the code to be recursive but as soon as there are nested objects involved I do not know how to reach the properties in B nor create the equivalent in C.
Example of an A object:
const data = {
a: "15",
b: "foo",
c: false,
d: {
da: 99,
db: [{
dba: "1.2",
dbb: true
}]
}
}
Example of a B object:
const targetType = {
a: 27,
b: "foofoo",
c: true,
d: {
da: "bar",
db: [{
dba: 4,
dbb: false
}]
}
}
Example of a C object -values from A, types from B:
const finalObject = {
a: 15,
b: "foo",
c: false,
d: {
da: "99",
db: [{
dba: 1.2,
dbb: true
}]
}
}
My function:
//data = object A
//targetType = object B
export function typeConversion(data: any, targetType: any) {
const resultObj = {};
Object.keys(data).forEach((key) => {
switch (typeof targetType[key]) {
case 'string':
resultObj[key] = data[key].toString();
break;
case 'boolean':
resultObj[key] = data[key] ? 'Yes' : 'No';
break;
case 'number':
resultObj[key] = Number(data[key]);
break;
//here is where it gets tricky:
case 'object':
if (Array.isArray(data[key])) {
const dataArray: any = [];
data[key].forEach((o) => {
//all objs in the array have the same shape, hence comparing to [0]
dataArray.push(typeConversion(o, targetType[key][0]));
});
resultObj[key] = dataArray;
} else {
const dataObj = {};
Object.keys(data[key]).forEach((subkey) => {
dataObj[subkey] = typeConversion(subkey, targetType[key][subkey]);
});
resultObj[key] = dataObj;
}
break;
}
});
return resultObj;
}
console.log(typeConversion(data, targetType))
The moment there is a nested object and typeConversion is called recursively, it will fail to find the path to the property in object B. I could add an optional parameter to the function for the 'parent property', but that would only work for one level of depth.
If there is a way to make this recursive, it can't be by coding the path to targetType[like][this]
.
All ideas welcome, perhaps I'm approaching the whole thing wrong.
Solution 1:[1]
I made some changes in your function to recursively create the final object. Although this is not Typescript
specific problem, I wonder what is the use case for this :)
const transform = (data, targetType) => {
let finalObject = {};
const keys = Object.keys(data);
for (const key of keys) {
// If key is Array [], recursively add each element in Array
if (data[key] instanceof Array) {
finalObject[key] = [];
for (let i = 0; i < data[key].length; i++) {
const res = transform(data[key][i], targetType[key][i]);
finalObject[key].push(res);
}
}
// If key is Object {}, recursively add Object keys
else if (data[key] instanceof Object) {
finalObject[key] = transform(data[key], targetType[key]);
}
// If key is Primitive, we can directly add key
else {
switch (typeof targetType[key]) {
case 'string':
finalObject[key] = data[key].toString();
break;
case 'boolean':
finalObject[key] = data[key] ? 'Yes' : 'No';
break;
case 'number':
finalObject[key] = Number(data[key]);
break;
}
}
}
return finalObject;
};
const data = {
a: "15",
b: "foo",
c: false,
d: {
da: 99,
db: [{
dba: "1.2",
dbb: true
}]
}
}
const targetType = {
a: 27,
b: "foofoo",
c: true,
d: {
da: "bar",
db: [{
dba: 4,
dbb: false
}]
}
}
const finalObject = transform(data, targetType);
console.log('Final Object : ', finalObject);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |