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

refactor: Error type narrowing for Result class #32705

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions lib/util/result.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,8 @@ describe('util/result', () => {
});

it('converts error to Result', () => {
const result = Result.err<string>('oops').catch(() =>
Result.ok<number>(42),
);
const error: Result<number, string> = Result.err<string>('oops');
const result = error.catch((_err) => Result.ok<number>(42));
expect(result).toEqual(Result.ok(42));
});

Expand Down Expand Up @@ -600,15 +599,15 @@ describe('util/result', () => {

describe('Catch', () => {
it('converts error to AsyncResult', async () => {
const result = await Result.err<string>('oops').catch(() =>
AsyncResult.ok(42),
);
const error: Result<number, string> = Result.err<string>('oops');
const result = await error.catch(() => AsyncResult.ok(42));
expect(result).toEqual(Result.ok(42));
});

it('converts error to Promise', async () => {
const fallback = Promise.resolve(Result.ok(42));
const result = await Result.err<string>('oops').catch(() => fallback);
const error: Result<number, string> = Result.err<string>('oops');
const result = await error.catch(() => fallback);
expect(result).toEqual(Result.ok(42));
});

Expand All @@ -619,9 +618,9 @@ describe('util/result', () => {
});

it('converts AsyncResult error to Result', async () => {
const result = await AsyncResult.err<string>('oops').catch(() =>
AsyncResult.ok<number>(42),
);
const error: AsyncResult<number, string> =
AsyncResult.err<string>('oops');
const result = await error.catch(() => AsyncResult.ok<number>(42));
expect(result).toEqual(Result.ok(42));
});
});
Expand Down
51 changes: 22 additions & 29 deletions lib/util/result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,28 +480,23 @@ export class Result<T extends Val, E extends Val = Error> {
}

catch<U extends Val = T, EE extends Val = E>(
fn: (err: E) => Result<U, E | EE>,
): Result<T | U, E | EE>;
fn: (err: E) => Result<U, EE>,
): Result<T | U, EE>;
catch<U extends Val = T, EE extends Val = E>(
fn: (err: E) => AsyncResult<U, E | EE>,
): AsyncResult<T | U, E | EE>;
fn: (err: E) => AsyncResult<U, EE>,
): AsyncResult<T | U, EE>;
catch<U extends Val = T, EE extends Val = E>(
fn: (err: E) => Promise<Result<U, E | EE>>,
): AsyncResult<T | U, E | EE>;
fn: (err: E) => Promise<Result<U, EE>>,
): AsyncResult<T | U, EE>;
catch<U extends Val = T, EE extends Val = E>(
fn: (
err: E,
) =>
| Result<U, E | EE>
| AsyncResult<U, E | EE>
| Promise<Result<U, E | EE>>,
): Result<T | U, E | EE> | AsyncResult<T | U, E | EE> {
fn: (err: E) => Result<U, EE> | AsyncResult<U, EE> | Promise<Result<U, EE>>,
): Result<T | U, EE> | AsyncResult<T | U, EE> {
if (this.res.ok) {
return this;
return this as never;
}

if (this.res._uncaught) {
return this;
return this as never;
}

try {
Expand Down Expand Up @@ -833,25 +828,23 @@ export class AsyncResult<T extends Val, E extends Val>
}

catch<U extends Val = T, EE extends Val = E>(
fn: (err: NonNullable<E>) => Result<U, E | EE>,
): AsyncResult<T | U, E | EE>;
fn: (err: NonNullable<E>) => Result<U, EE>,
): AsyncResult<T | U, EE>;
catch<U extends Val = T, EE extends Val = E>(
fn: (err: NonNullable<E>) => AsyncResult<U, E | EE>,
): AsyncResult<T | U, E | EE>;
fn: (err: NonNullable<E>) => AsyncResult<U, EE>,
): AsyncResult<T | U, EE>;
catch<U extends Val = T, EE extends Val = E>(
fn: (err: NonNullable<E>) => Promise<Result<U, E | EE>>,
): AsyncResult<T | U, E | EE>;
fn: (err: NonNullable<E>) => Promise<Result<U, EE>>,
): AsyncResult<T | U, EE>;
catch<U extends Val = T, EE extends Val = E>(
fn: (
err: NonNullable<E>,
) =>
| Result<U, E | EE>
| AsyncResult<U, E | EE>
| Promise<Result<U, E | EE>>,
): AsyncResult<T | U, E | EE> {
const caughtAsyncResult = this.asyncResult.then((result) =>
// eslint-disable-next-line promise/no-nesting
result.catch(fn as never),
) => Result<U, EE> | AsyncResult<U, EE> | Promise<Result<U, EE>>,
): AsyncResult<T | U, EE> {
const caughtAsyncResult: Promise<Result<T, EE>> = this.asyncResult.then(
(result) =>
// eslint-disable-next-line promise/no-nesting
result.catch(fn as never),
);
return AsyncResult.wrap(caughtAsyncResult);
}
Expand Down