Merge requirements

Hey everybody,

see the following example (Remix app):

export class LoaderFunctionArgs extends Context.Tag("LoaderFunctionArgs")<
  LoaderFunctionArgs,
  Remix.LoaderFunctionArgs
>() {}

export class ActionFunctionArgs extends Context.Tag("ActionFunctionArgs")<
  ActionFunctionArgs,
  Remix.ActionFunctionArgs
>() {}

export function params() {
  return Effect.flatMap(
    (args: Remix.LoaderFunctionArgs | Remix.ActionFunctionArgs) =>
      Effect.succeed(args.params)
  );
}

export function parseParams<T extends z.ZodTypeAny>(schema: T) {
  return Effect.flatMap((params: Params) => Zod.parse(schema, params));
}

export const LoaderParams = LoaderFunctionArgs.pipe(params());
export const ActionParams = ActionFunctionArgs.pipe(params());

export function parseLoaderParams<T extends z.ZodTypeAny>(schema: T) {
  return LoaderParams.pipe(parseParams(schema));
}
export function parseActionParams<T extends z.ZodTypeAny>(schema: T) {
  return ActionParams.pipe(parseParams(schema));
}

export function makeLoader<A, E>(
  program: Effect.Effect<A, E, LoaderFunctionArgs>
) {
  return (args: Remix.LoaderFunctionArgs) =>
    run(program.pipe(Effect.provideService(LoaderFunctionArgs, args)), {
      signal: args.request.signal,
    });
}

export function makeAction<A, E>(
  program: Effect.Effect<A, E, ActionFunctionArgs>
) {
  return (args: Remix.ActionFunctionArgs) =>
    run(program.pipe(Effect.provideService(ActionFunctionArgs, args)), {
      signal: args.request.signal,
    });
}


Effect is really mind-blowing. But:

As you can see I now have duplicate helpers for actions and loaders.

It would be nice if parseParams would return an effect requiring LoaderFunctionArgs or ActionFunctionArgs (not both) instead of having parseLoaderParams and parseActionParams.

Is there some way to ‘merge’ both requirements into one while also keeping separate makeLoader and makeAction helpers?

How would I provide such a service inside makeLoader or makeAction?
Was this page helpful?