Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More ergonomic match #497

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open

Conversation

braxtonhall
Copy link

@braxtonhall braxtonhall commented Oct 9, 2023

When writing a match in neverthrow, the ok and err callbacks must have the same ReturnType in their signature. This means the following code results in an error

declare const result: Result<string, number>
const matchResult = result.match(
	(value: string) => !!value,
	(value: number) => BigInt(10),
//	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// TS2345: Argument of type  (value: number) => bigint  is not assignable to parameter of type  (e: number) => boolean 
// Type  bigint  is not assignable to type  boolean
)

This can be fixed by annotating the callbacks or the match application with more generic types

declare const result: Result<string, number>
const matchResultA = result.match(
	(value: string): boolean | bigint => !!value,
	(value: number) => BigInt(10),
)
const matchResultB = result.match<boolean | bigint>(
	(value: string) => !!value,
	(value: number) => BigInt(10),
)

However this is pretty inconvenient!

Instead, match can infer that the result is the union of whatever ok returns, and whatever err returns

  interface Result<T, E> {
    // ...
-   match<A>(ok: (t: T) => A, err: (e: E) => A): A;
+   match<A, B>(ok: (t: T) => A, err: (e: E) => B): A | B;
    // ...
  }
declare const result: Result<string, number>
const matchResult = result.match(
	(value: string) => !!value,
	(value: number) => BigInt(10),
)

true satisfies typeof matchResult
BigInt(10) satisfies typeof matchResult

Unfortunately, this would be a breaking change! Anyone who had already annotated their method call would now get an error

declare const result: Result<string, number>
const matchResult = result.match<boolean | bigint>(
//                               ~~~~~~~~~~~~~~~~
// TS2558: Expected  2  type arguments, but got  1 
	(value: string) => !!value,
	(value: number) => BigInt(10),
)

To support legacy code, we can add a default to the second type argument

  interface Result<T, E> {
    // ...
-   match<A>(ok: (t: T) => A, err: (e: E) => A): A;
+   match<A, B = A>(ok: (t: T) => A, err: (e: E) => B): A | B;
    // ...
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant