Main review
Your code works well in most cases, but the biggest change I recommend in order to skip over false positives would be to change the following lines
if (obj.hasOwnProperty(objKey)) {
return JSON.stringify(obj[objKey]) === JSON.stringify(objValue)
}
to the following (move JSON.stringify(obj[objKey]) === JSON.stringify(objValue)
into the conditional statement and return true):
if (obj.hasOwnProperty(objKey) && JSON.stringify(obj[objKey]) === JSON.stringify(objValue)) {
return true;
}
As 200_success pointed out, your code returns false when a key exists in one part of the whole object but doesn't match and another key exists elsewhere which does match. This change will check whether a key matches first and proceeds to perform the recursive search for another key with matching value.
In the following code snippet, I changed the code to JavaScript so it could be run here in this post.
function checkNestedObjectByKeyValue(obj, objKey, objValue) {
if (typeof obj !== "object") return false;
if (obj.hasOwnProperty(objKey) && JSON.stringify(obj[objKey]) === JSON.stringify(objValue)) {
return true;
}
for (const value of Object.values(obj)) {
if (checkNestedObjectByKeyValue(value, objKey, objValue))
return true;
}
return false;
}
const obj = {
a: {
b: {
a3: "v2",
c1: ["1", "2"],
c2: "3"
},
b2: "values",
b3: {
c5: "v"
},
},
a2: ["v1", "v2"],
a3: "v1"
};
console.log(checkNestedObjectByKeyValue(obj, "a3", "v1"));
console.log(checkNestedObjectByKeyValue(obj, "a3", "v2"));
console.log(checkNestedObjectByKeyValue(obj, "a2", ["v1", "v2"]));
console.log(checkNestedObjectByKeyValue(obj, "b3", {
c5: "v"
}));
// Added a check that should return false
console.log(checkNestedObjectByKeyValue(obj, "b2", "novalue"));
If the pattern of object properties is:
- first level property name
/^a\d*$/
- second level property name
/^b\d*$/
- third level property name
/^c\d*$/
- etc.
Then this may not be necessary.
Other thoughts
When I first ran your code, I received an error: Argument of type '{ c5: string; }' is not assignable to parameter of type 'string | string[]'.
which referenced the following line:
checkNestedObjectByKeyValue(obj, "b3", { c5: "v" })
I resolved this by adding | object
to the objValue
parameter as follows:
function checkNestedObjectByKeyValue(
obj: Record<string, any>,
objKey: string,
objValue: string | Array<string> | object
): boolean {