TypeScript Error Handling with Discriminated Unions

How can I annotate the type so that based on the input parameter it disambiguate the errors of the effect?

class TestCommand extends Schema.TaggedClass<TestCommand>()(
    "commands/test-command",
    {
        test: Schema.NonEmptyString,
    },
) {}

class TestError extends Data.TaggedError("errors/test-error")<{}> {}

const handlerTestCommand = (cmd: typeof TestCommand.Type) => Effect.gen(function*() {
  yield* Effect.log(`test command run: ${cmd.test}`)
  yield* Effect.fail(new TestError())
})

class DataCommand extends Schema.TaggedClass<DataCommand>()(
    "commands/data-command",
    {
        data: Schema.NonEmptyString,
    },
) {}

class DataError extends Data.TaggedError("errors/data-error")<{}> {}

const handlerDataCommand = (cmd: typeof DataCommand.Type) => Effect.gen(function*() {
  yield* Effect.log(`data command run: ${cmd.data}`)
  yield* Effect.fail(new DataError())
})

const DomainCommand = Schema.Union(TestCommand, DataCommand)

interface AggregateState {
  done: boolean;
}

class Aggregate {
  constructor(private readonly state: SynchronizedRef.SynchronizedRef<AggregateState>) {}

  static make = Effect.andThen(SynchronizedRef.make<AggregateState>({ done: false }), (ref) => new this(ref))

  execute(command: typeof DomainCommand.Type) {

    return Effect.gen(function*() {
      const handler = Match.type<typeof DomainCommand.Type>().pipe(
        Match.tag("commands/data-command", handlerDataCommand),
        Match.tag("commands/test-command", handlerTestCommand),
        Match.exhaustive
      )

      yield* handler(command)
    })
  }
}

const program = Effect.gen(function*() {
  const myAggregate = yield* Aggregate.make

  const testCmd = yield* Schema.decode(TestCommand)({
    _tag: "commands/test-command",
    test: "test data"
  })

  // This is Effect.Effect<void, TestError | DataError, never>
  // I would like it to be Effect.Effect<void, TestError, never>
  yield* myAggregate.execute(testCmd)
})
Was this page helpful?