Effect-TS / effect

An ecosystem of tools to build robust applications in TypeScript
https://effect.website
MIT License
6.3k stars 200 forks source link

From Discord: Refining Error Channels in TypeScript Effects Without Tagged Errors #3004

Open effect-bot opened 3 weeks ago

effect-bot commented 3 weeks ago

Summary

Summary

The conversation revolves around refining error channels in TypeScript Effects without using tagged errors. The initial code snippet provided by the user demonstrates a custom combinator refineErrorOrDie that refines the error channel by mapping specific errors to custom tagged errors or dying otherwise. The user also mentions an alternative approach using Effect.catchAll, which requires type annotations and is not ideal.

Another participant suggests using .catch, but the user clarifies that they want to use refinements instead of discriminators. The conversation touches on the idea of using mapError, flip, filterOrDie, and flip, but this approach is deemed ugly. The user mentions that there used to be a refineOrDie function that was removed for being unsafe and misleading.

The user expresses a preference for a single combinator to handle error refinement rather than flipping between the A/E channels. The suggestion is made to create an issue requesting the return of refineErrorOrDie and refineErrorTagOrDie.

Key Takeaways

  1. Custom Combinator: The user has a custom combinator refineErrorOrDie for refining error channels.
  2. Alternative Approach: Using Effect.catchAll with type annotations is an alternative but not ideal.
  3. Refinement vs. Discriminator: The user prefers using refinements over discriminators for error handling.
  4. Removed Functionality: There used to be a refineOrDie function that was removed for safety concerns.
  5. Single Combinator Preference: The user prefers a single combinator for error refinement rather than multiple steps.
  6. Feature Request: There's a suggestion to create an issue to bring back refineErrorOrDie and refineErrorTagOrDie.

Action Items

Discord thread

https://discord.com/channels/795981131316985866/1252232384070422598

stevebluck commented 3 weeks ago

I would like a refineOrDie method which refines the error channel or dies based on custom logic such as refinements. This is useful for cases where I do not have a tagged error and wish to map an E to some E1 or die.

Something like so:

export const refineErrorOrDie =
  <A, E, E1>(f: (e: E) => Option.Option<E1>) =>
  (self: Effect.Effect<A, E>): Effect.Effect<A, E1> =>
    self.pipe(
      Effect.catchAll((e) =>
        Option.match(f(e), {
          onNone: () => Effect.die(e),
          onSome: Effect.fail
        })
      )
    )

I can accomplish the same thing with a catchAll but it requires some type annotations which isn't ideal:

Effect.catchAll((e) => {
  if (isUniqueConstraintError(e)) {
    return Effect.fail<Chip.AlreadyExists | Team.NotFound>(new Chip.AlreadyExists())
  }

  if (isForegienKeyConstraintError(e)) {
    return Effect.fail<Chip.AlreadyExists | Team.NotFound>(new Team.NotFound())
  }

  return Effect.die(e)
})
tim-smart commented 2 weeks ago

You can use Effect.catchIf(isSomeError, Effect.die)