I am needing a function that takes any object and returns true/false if every child meets a condition. Currently that condition is that the property is truthy. So null and undefined should return false, but a value of false is a pass.
The project I'm working in is in Typescript, but this applies to vanilla JS as well, and I am also able to use lodash.
I've started with this function so far:
function CheckAllPropertiesDefined(obj){
if (!obj) {
return false;
}
for (const key in obj) {
if (o[key] === null || o[key] === undefined) {
return false;
}
}
return true;
}
However the requirements of what I'm doing changed (no longer a flat object) and I realised it's not working for nested properties.
The outcome of running it against this object is true, when it shouldn't be:
const obj = {
prop1: true,
prop2: true,
prop3: {
prop3a: false,
},
prop4: {
test: null,
foo: false,
child: {
child2: null,
},
},
};
It should return false because prop4.test
and prop4.child.child2
are null. I am figuring some recursion is necessary.
I generally prefer to split apart the traversal of the object from the action we perform on it. Here, I would write a generic function that can apply a predicate against any (scalar) node, and recurses on objects or arrays. Then we can simply call it with a function that tests that the node is not null
or undefined
to get back a function to use in testing an object. This is an example:
const checkAllDeep = (pred) => (xs) =>
Array .isArray (xs)
? xs .every (x => checkAllDeep (pred) (x))
: xs && typeof xs == 'object'
? Object .entries (xs) .every (([k, v]) => checkAllDeep (pred) (v))
: pred (xs)
const checkAllPropertiesDefined = checkAllDeep (x => x !== null && x !== undefined)
const obj = {prop1: true, prop2: true, prop3: {prop3a: false}, prop4: {test: null, foo: false, child: {child2: null}}}
console .log (checkAllPropertiesDefined (obj))
Later if we want to change the predicate (we want to accept null
but not undefined
, for instance), it's easy to find. And we could write other functions such as const allPropsAreStrings (checkAllDeep ((x) => typeof x == 'string')
quite simply.