I love Ramda, but my organisation is falling away from it - we have hires who don't think in FP, and Typescript and Ramda fight somewhat.
You can coax Ramda code to work in Typescript by strategically adding as
in the right places. But it's often quite
hard work -- harder work than refactoring away from Ramda before converting the plain JS to TS.
Here's some patterns for refactoring away from Ramda. In most cases, applying any of these changes leaves you with less clear code than you started with. But you can now apply more refactorings - extract function, extract method, pulling up IIAF parameters then removing unnecessary IIAF calls, will lead you towards clean code.
You can normally use a meaningless parameter name like x
as in these examples, then continue refactoring until it's no
longer there. Perhaps at the top level it will remain. Rename it to be meaningful.
I don't try to be exhaustive. Many conversions are obvious (indeed, these ones are!) and once you get the general idea, you'll find it easy to convert functions not described here.
It's often valuable to extract-function or extract-variable until functions calls are boiled down to their essence. Once you have refactored those, you can use IDE tooling to inline the refactored code.
compose(f1, f2, f3);
x => f1(f2(f3(x)));
Rename to compose
and reverse the parameter order. Test. Now refactor from compose
.
pipe(f1, f2, f3)
compose(f3, f2, f1);
ifElse(pred, thenFn, elseFn)
x => pred(x) ? thenFn(x) : elseFn(x)
You can very often now refactor pred(x)
into a simple predicate, for example:
ifElse(propEq('brown', 'hair), setLabel('brunette'), setLabel('blonde'));
-->
x => propEq('brown', 'hair)(x) ? setLabel('brunette')(x) : setLabel('blonde')(x)
-->
x => x.hair == 'brown' ? setLabel('brunette')(x) : setLabel('blonde')(x)
... and continue simplifying from there.
'Convert to if-else' from your IDE's refactoring menu may now be valuable.
when(pred, f1)
x => pred(x) ? f1(x) : x
cf ifElse
assoc(label, value)
x => ({ ...x, [label]: value })
evolve({
name1: f1,
name2: f2,
name3: f3,
})
x => ({
...x,
name1: f1(x),
name2: f2(x),
name3: f3(x),
})
converge(f0, [ f1, f2, f3 ])
x => f0(f1(x), f2(x), f3(x))