I want to write a function whose specifications is described in the piece of code below which is the current implementation I have. It does work. However I have been trying for a while to write it pointfree and entirely as a composition of ramda functions and could not find a solution. The issue is linked to obj => map(key => recordSpec[key](obj[key])
which I cannot reduce in a way that I can write the whole thing pointfree.
How could I do?
/**
* check that an object :
* - does not have any extra properties than the expected ones (strictness)
* - that its properties follow the defined specs
* Note that if a property is optional, the spec must include that case
* @param {Object.<String, Predicate>} recordSpec
* @returns {Predicate}
* @throws when recordSpec is not an object
*/
function isStrictRecordOf(recordSpec) {
return allPass([
// 1. no extra properties, i.e. all properties in obj are in recordSpec
// return true if recordSpec.keys - obj.keys is empty
pipe(keys, flip(difference)(keys(recordSpec)), isEmpty),
// 2. the properties in recordSpec all pass their corresponding predicate
// For each key, execute the corresponding predicate in recordSpec on the
// corresponding value in obj
pipe(obj => map(key => recordSpec[key](obj[key]), keys(recordSpec)), all(identity)),
]
)
}
For instance,
isStrictRecordOf({a : isNumber, b : isString})({a:1, b:'2'}) -> true
isStrictRecordOf({a : isNumber, b : isString})({a:1, b:'2', c:3}) -> false
isStrictRecordOf({a : isNumber, b : isString})({a:1, b:2}) -> false
One way to achieve this would be to use R.where
, which takes a spec object like your recordSpec
and applies each predicate with the value from the corresponding keys of the second object.
Your function would then look like:
const isStrictRecordOf = recordSpec => allPass([
pipe(keys, flip(difference)(keys(recordSpec)), isEmpty),
where(recordSpec)
])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With