Skip to content

Commit

Permalink
fix using unions with Match.withReturnType (#3099)
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-smart authored Jun 27, 2024
1 parent e86211a commit a047af9
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .changeset/brown-wasps-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": patch
---

fix using unions with Match.withReturnType
8 changes: 4 additions & 4 deletions packages/effect/src/Match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export const typeTags: <I>() => <
*/
export const withReturnType: <Ret>() => <I, F, R, A, Pr, _>(
self: Matcher<I, F, R, A, Pr, _>
) => Ret extends ([A] extends [never] ? any : A) ? Matcher<I, F, R, A, Pr, Ret>
) => [Ret] extends [[A] extends [never] ? any : A] ? Matcher<I, F, R, A, Pr, Ret>
: "withReturnType constraint does not extend Result type" = internal.withReturnType

/**
Expand Down Expand Up @@ -496,11 +496,11 @@ export const instanceOfUnsafe: <A extends abstract new(...args: any) => any>(
* @category conversions
* @since 1.0.0
*/
export const orElse: <RA, Ret, B extends Ret>(
f: (b: RA) => B
export const orElse: <RA, Ret, F extends (_: RA) => Ret>(
f: F
) => <I, R, A, Pr>(
self: Matcher<I, R, RA, A, Pr, Ret>
) => [Pr] extends [never] ? (input: I) => Unify<B | A> : Unify<B | A> = internal.orElse
) => [Pr] extends [never] ? (input: I) => Unify<ReturnType<F> | A> : Unify<ReturnType<F> | A> = internal.orElse

/**
* @category conversions
Expand Down
39 changes: 20 additions & 19 deletions packages/effect/src/internal/matcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,11 @@ export const typeTags = <I>() =>
}

/** @internal */
export const withReturnType =
<Ret>() =>
<I, F, R, A, Pr, _>(self: Matcher<I, F, R, A, Pr, _>): Ret extends ([A] extends [never] ? any
: A) ? Matcher<I, F, R, A, Pr, Ret>
: "withReturnType constraint does not extend Result type" => self as any
export const withReturnType = <Ret>() =>
<I, F, R, A, Pr, _>(self: Matcher<I, F, R, A, Pr, _>): [Ret] extends [
[A] extends [never] ? any : A
] ? Matcher<I, F, R, A, Pr, Ret>
: "withReturnType constraint does not extend Result type" => self as any

/** @internal */
export const when = <
Expand Down Expand Up @@ -512,23 +512,24 @@ export const instanceOfUnsafe: <A extends abstract new(...args: any) => any>(
) => SafeRefinement<InstanceType<A>, InstanceType<A>> = instanceOf

/** @internal */
export const orElse = <RA, Ret, B extends Ret>(f: (b: RA) => B) =>
<I, R, A, Pr>(
self: Matcher<I, R, RA, A, Pr, Ret>
): [Pr] extends [never] ? (input: I) => Unify<A | B> : Unify<A | B> => {
const result = either(self)
export const orElse =
<RA, Ret, F extends (_: RA) => Ret>(f: F) =>
<I, R, A, Pr>(self: Matcher<I, R, RA, A, Pr, Ret>): [Pr] extends [never] ? (input: I) => Unify<ReturnType<F> | A>
: Unify<ReturnType<F> | A> =>
{
const result = either(self)

if (Either.isEither(result)) {
// @ts-expect-error
return result._tag === "Right" ? result.right : f(result.left)
}

if (Either.isEither(result)) {
// @ts-expect-error
return result._tag === "Right" ? result.right : f(result.left)
}

// @ts-expect-error
return (input: I) => {
const a = result(input)
return a._tag === "Right" ? a.right : f(a.left)
return (input: I) => {
const a = result(input)
return a._tag === "Right" ? a.right : f(a.left)
}
}
}

/** @internal */
export const orElseAbsurd = <I, R, RA, A, Pr, Ret>(
Expand Down
21 changes: 21 additions & 0 deletions packages/effect/test/Match.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -819,4 +819,25 @@ describe("Match", () => {
M.orElse(() => "else")
)
})

it("withReturnType union", () => {
const match = pipe(
M.type<string>(),
M.withReturnType<"a" | "b">(),
M.when("A", (_) => "a"),
M.orElse((_) => "b")
)
expect(match("A")).toEqual("a")
expect(match("a")).toEqual("b")
})

it("withReturnType union mismatch", () => {
pipe(
M.type<string>(),
M.withReturnType<"a" | "b">(),
M.when("A", (_) => "a"),
// @ts-expect-error
M.orElse((_) => "c")
)
})
})

0 comments on commit a047af9

Please sign in to comment.