Effect CommunityEC
Effect Community3y ago
65 replies
WIP

Using TS and `@effect/data` / `fp-ts` for `getInitPath` function

I am picking up TS and @effect/data / fp-ts again and I find myself having always the same grievance. Maybe am I approaching it the wrong way.

Take this function (which I think is perfectly fine) where Stuff is { segments: string[], foo: any }:
const getInitPath = (x: Stuff) => x.segments.slice(0, -1);

If I wanted to use utils such as flow, get and init, I don't see any way other than the following to get it to compile and infer types correctly:
const getInitPath = flow(
    R.get('segments'),
    O.flatMap(init),
    O.getOrElse(() => [] as string[])
) satisfies (x: { segments: string[] }) => unknown

(I can't blame ReadonlyRecord for having to provide a type wider than Stuff since Stuff is not a record. This one is on me.)

In this situation I would reach for pipe, which lets me set the input and return types, but if I have a parameter I'm going to use it:
const getInitPath = (x: Stuff): string[] =>
    pipe(init(x.segments), O.getOrElse(() => []));

Then I would naturally come to the conclusion that there is no value in having that Option in the way since I am discarding it immediately, and I would end up with my first implementation using slice.

In this process I'm little by little totally evacuating every fp-ts abstraction. I find myself doing that a lot.

I don't know exactly what could or should be improved, but I notice that get does not enable specifying the input type. If I could write get<{ segments: string[] }>('segments'), at least I could use flow and get without that satisfies. Or if init could optionally take a lazy value as a fallback so as to avoid creating an Option, I would maybe use it, because it reads well.

My JS code use to be littered with it, but in general I find it quite hard to use flow.

Is your experience similar than mine in any way?
Was this page helpful?