November 18, 2018
Ramda: propOr vs prop + defaultTo are not the same
I thought these two lines would be equivalent, but they aren’t
propOr("Canada", "country", address);
pipe(prop("country"), defaultTo("Canada"))(address);
The goal of these lines to look up a country
property on an address
object, and provide a fallback value of Canada
if there isn’t something useful there. What’s the difference? That depends how you define something useful.
defaultTo
counts null
, undefined
, and NaN
as not useful values. propOr
will considers any value as useful, as long as the requested property exists.
That means if address
looks like this:
const address = {
addressLine1: "18 Ork St",
addressLine2: "Suite 105",
postalCode: "L4L4L4",
province: "ON",
};
both propOr
and the pipe
-based function return Canada
propOr("Canada", "country", address) == pipe(prop("country"), defaultTo("Canada"))(address);
// returns `true`
but, if address
looks like this (notice country: null
here)
const address = {
addressLine1: "18 Ork St",
addressLine2: "Suite 105",
postalCode: "L4L4L4",
province: "ON",
country: null,
};
then
propOr("Canada", "country", address) == pipe(prop("country"), defaultTo("Canada"))(address);
// returns `false`
Why?
propOr
sees the country
property is set, and passes its value along to us, even if it is set to null
(or undefined
, or NaN
).
The combined pipe
function’s defaultTo
will replace undefined
, null
, or NaN
with the default value, so null
value is replaced with the default value.
So which one do I use?
It depends. If your system accepts values of null
or undefined
as meaningful, use propOr
. If you need to guard your system against null
or undefined
, use the piped version.