Skip to content

Commit 575969f

Browse files
committed
refactor(lib): remove resultAsync promise error handling, add missing tests
1 parent 4ddb95f commit 575969f

19 files changed

Lines changed: 800 additions & 197 deletions

src/result.ts

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -480,31 +480,29 @@ export class Result<TValue = Unit, TError = string> {
480480
/**
481481
* Maps the value successful Result to a new async value wrapped in a ResultAsync
482482
* @param projection a function given the value of the current Result which returns a Promise of some value
483-
* @param errorHandler a function that converts the error of the rejected Promise to a failed Result
483+
484484
* @returns
485485
*/
486486
mapAsync<TNewValue>(
487-
projection: FunctionOfTtoK<TValue, Promise<Some<TNewValue>>>,
488-
errorHandler?: ErrorHandler<TError>
487+
projection: FunctionOfTtoK<TValue, Promise<Some<TNewValue>>>
489488
): ResultAsync<TNewValue, TError> {
490489
return this.isSuccess
491-
? ResultAsync.from(projection(this.getValueOrThrow()), errorHandler)
490+
? ResultAsync.from(projection(this.getValueOrThrow()))
492491
: ResultAsync.failure(this.getErrorOrThrow());
493492
}
494493

495494
/**
496495
* Maps the error of a failed Result to a new async value wrapped in a ResultAsync
497496
* @param projection a function given the error of the current Result which returns a Promise of some value
498-
* @param errorHandler a function that converts the error of the rejected Promise to a failed Result
497+
499498
* @returns
500499
*/
501500
mapFailureAsync(
502-
projection: FunctionOfTtoK<TError, Promise<Some<TValue>>>,
503-
errorHandler?: ErrorHandler<TError>
501+
projection: FunctionOfTtoK<TError, Promise<Some<TValue>>>
504502
): ResultAsync<TValue, TError> {
505503
return this.isSuccess
506504
? ResultAsync.from(this)
507-
: ResultAsync.from(projection(this.getErrorOrThrow()), errorHandler);
505+
: ResultAsync.from(projection(this.getErrorOrThrow()));
508506
}
509507

510508
/**
@@ -523,11 +521,10 @@ export class Result<TValue = Unit, TError = string> {
523521
/**
524522
* Maps a successful Result to a new ResultAsync
525523
* @param projection
526-
* @param errorHandler a function that converts the error of the rejected Promise to a failed Result
524+
527525
*/
528526
bindAsync<TNewValue>(
529-
projection: FunctionOfTtoK<TValue, Promise<Result<TNewValue, TError>>>,
530-
errorHandler?: ErrorHandler<TError>
527+
projection: FunctionOfTtoK<TValue, Promise<Result<TNewValue, TError>>>
531528
): ResultAsync<TNewValue, TError>;
532529
/**
533530
* Maps a successful Result to a new ResultAsync
@@ -539,14 +536,13 @@ export class Result<TValue = Unit, TError = string> {
539536
/**
540537
* Maps a successful Result to a new ResultAsync
541538
* @param projection
542-
* @param errorHandler a function that converts the error of the rejected Promise to a failed Result
539+
543540
* @returns
544541
*/
545542
bindAsync<TNewValue>(
546543
projection:
547544
| FunctionOfTtoK<TValue, Promise<Result<TNewValue, TError>>>
548-
| FunctionOfTtoK<TValue, ResultAsync<TNewValue, TError>>,
549-
errorHandler?: ErrorHandler<TError>
545+
| FunctionOfTtoK<TValue, ResultAsync<TNewValue, TError>>
550546
): ResultAsync<TNewValue, TError> {
551547
if (this.isFailure) {
552548
return ResultAsync.failure(this.getErrorOrThrow());
@@ -555,7 +551,7 @@ export class Result<TValue = Unit, TError = string> {
555551
const resultAsyncOrPromise = projection(this.getValueOrThrow());
556552

557553
return isPromise(resultAsyncOrPromise)
558-
? ResultAsync.from<TNewValue, TError>(resultAsyncOrPromise, errorHandler)
554+
? ResultAsync.from<TNewValue, TError>(resultAsyncOrPromise)
559555
: resultAsyncOrPromise;
560556
}
561557

@@ -588,23 +584,17 @@ export class Result<TValue = Unit, TError = string> {
588584
/**
589585
* Executes an async action if the Result succeeded
590586
* @param action a function given the Result's value returns a Promise
591-
* @param errorHandler a function that converts the error of the rejected Promise to a failed Result
587+
592588
* @returns a ResultAsync
593589
*/
594-
tapAsync(
595-
action: AsyncActionOfT<TValue>,
596-
errorHandler?: ErrorHandler<TError>
597-
): ResultAsync<TValue, TError> {
590+
tapAsync(action: AsyncActionOfT<TValue>): ResultAsync<TValue, TError> {
598591
if (this.isFailure) {
599592
return ResultAsync.failure(this.getErrorOrThrow());
600593
}
601594

602595
const value = this.getValueOrThrow();
603596

604-
return ResultAsync.from(
605-
action(value).then<Some<TValue>>(() => value),
606-
errorHandler
607-
);
597+
return ResultAsync.from(action(value).then<Some<TValue>>(() => value));
608598
}
609599

610600
/**
@@ -749,7 +739,7 @@ export class Result<TValue = Unit, TError = string> {
749739
}
750740
};
751741

752-
return ResultAsync.from<TValue, TError>(promiseFactory(), errorHander);
742+
return ResultAsync.from<TValue, TError>(promiseFactory());
753743
}
754744

755745
/**

src/resultAsync.ts

Lines changed: 84 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { ErrorHandler } from '.';
21
import { Result } from './result';
32
import { Unit } from './unit';
43
import {
@@ -31,41 +30,31 @@ export class ResultAsync<TValue = Unit, TError = string> {
3130
/**
3231
* Creates a new ResultAsync from the given Promise
3332
* @param value a Promise resolving to a Result
34-
* @param errorHandler
3533
*/
3634
static from<TValue, TError>(
37-
value: Promise<Result<TValue, TError>>,
38-
errorHandler?: ErrorHandler<TError>
35+
value: Promise<Result<TValue, TError>>
3936
): ResultAsync<TValue, TError>;
4037
/**
4138
* Creates a new ResultAsync from the given Promise
4239
* @param value a Promise which will be converted into a successful Result if it resolves
4340
* and a failed Result if it rejects
4441
*/
4542
static from<TValue, TError>(
46-
value: Promise<Some<TValue>>,
47-
errorHandler?: ErrorHandler<TError>
43+
value: Promise<Some<TValue>>
4844
): ResultAsync<TValue, TError>;
4945

5046
static from<TValue, TError>(
5147
value:
5248
| Result<TValue, TError>
5349
| Promise<Result<TValue, TError>>
54-
| Promise<Some<TValue>>,
55-
errorHandler?: ErrorHandler<TError>
50+
| Promise<Some<TValue>>
5651
): ResultAsync<TValue, TError> {
5752
if (isPromise(value)) {
58-
let promise = value.then((v) =>
59-
v instanceof Result ? v : Result.success<TValue, TError>(v)
53+
return new ResultAsync(
54+
value.then((v) =>
55+
v instanceof Result ? v : Result.success<TValue, TError>(v)
56+
)
6057
);
61-
62-
if (isFunction(errorHandler)) {
63-
promise = promise.catch((error) =>
64-
Result.failure<TValue, TError>(errorHandler(error))
65-
);
66-
}
67-
68-
return new ResultAsync(promise);
6958
} else if (value instanceof Result) {
7059
return new ResultAsync(Promise.resolve(value));
7160
}
@@ -293,24 +282,24 @@ export class ResultAsync<TValue = Unit, TError = string> {
293282

294283
/**
295284
* Converts the inner value of a successful Result to a new value.
296-
* If the Result failed, no action is taken
297-
* @param projection function which accepts the current value as a parameter and returns a new value
285+
* @param projection function which accepts the current value as a parameter and returns a Promise containing
286+
* the new value
298287
*/
299288
map<TNewValue>(
300-
projection: FunctionOfTtoK<TValue, Some<TNewValue>>
289+
projection: FunctionOfTtoK<TValue, Promise<Some<TNewValue>>>
301290
): ResultAsync<TNewValue, TError>;
302291
/**
303292
* Converts the inner value of a successful Result to a new value.
304-
* @param projection function which accepts the current value as a parameter and returns a Promise containing
305-
* the new value
293+
* If the Result failed, no action is taken
294+
* @param projection function which accepts the current value as a parameter and returns a new value
306295
*/
307296
map<TNewValue>(
308-
projection: FunctionOfTtoK<TValue, Promise<Some<TNewValue>>>
297+
projection: FunctionOfTtoK<TValue, Some<TNewValue>>
309298
): ResultAsync<TNewValue, TError>;
310299
map<TNewValue>(
311300
projection:
312-
| FunctionOfTtoK<TValue, Some<TNewValue>>
313301
| FunctionOfTtoK<TValue, Promise<Some<TNewValue>>>
302+
| FunctionOfTtoK<TValue, Some<TNewValue>>
314303
): ResultAsync<TNewValue, TError> {
315304
return new ResultAsync(
316305
this.value.then((r) => {
@@ -329,16 +318,20 @@ export class ResultAsync<TValue = Unit, TError = string> {
329318
);
330319
}
331320

321+
/**
322+
*
323+
* @param projection
324+
*/
332325
mapError<TNewError>(
333-
projection: FunctionOfTtoK<TError, Some<TNewError>>
326+
projection: FunctionOfTtoK<TError, Promise<Some<TNewError>>>
334327
): ResultAsync<TValue, TNewError>;
335328
mapError<TNewError>(
336-
projection: FunctionOfTtoK<TError, Promise<Some<TNewError>>>
329+
projection: FunctionOfTtoK<TError, Some<TNewError>>
337330
): ResultAsync<TValue, TNewError>;
338331
mapError<TNewError>(
339332
projection:
340-
| FunctionOfTtoK<TError, Some<TNewError>>
341333
| FunctionOfTtoK<TError, Promise<Some<TNewError>>>
334+
| FunctionOfTtoK<TError, Some<TNewError>>
342335
): ResultAsync<TValue, TNewError> {
343336
return new ResultAsync(
344337
this.value.then((r) => {
@@ -357,6 +350,43 @@ export class ResultAsync<TValue = Unit, TError = string> {
357350
);
358351
}
359352

353+
mapFailure(
354+
projection: FunctionOfTtoK<TError, Promise<Some<TValue>>>
355+
): ResultAsync<TValue, TError>;
356+
/**
357+
* Converts a failed Result into a successful one
358+
* @param projection a function that maps the error of the current Result to a value
359+
* @returns A successful Result using the current Result's value if it succeeded and the projection's value if it failed
360+
*/
361+
mapFailure(
362+
projection: FunctionOfTtoK<TError, Some<TValue>>
363+
): ResultAsync<TValue, TError>;
364+
mapFailure(
365+
projection:
366+
| FunctionOfTtoK<TError, Promise<Some<TValue>>>
367+
| FunctionOfTtoK<TError, Some<TValue>>
368+
): ResultAsync<TValue, TError> {
369+
return new ResultAsync(
370+
this.value.then((r) => {
371+
if (r.isSuccess) {
372+
return r;
373+
}
374+
375+
const valueOrPromise = projection(r.getErrorOrThrow());
376+
377+
if (isPromise(valueOrPromise)) {
378+
return valueOrPromise.then((v) => Result.success(v));
379+
}
380+
381+
return Result.success(valueOrPromise);
382+
})
383+
);
384+
}
385+
386+
/**
387+
*
388+
* @param projection
389+
*/
360390
bind<TNewValue>(
361391
projection: FunctionOfTtoK<TValue, Result<TNewValue, TError>>
362392
): ResultAsync<TNewValue, TError>;
@@ -385,13 +415,17 @@ export class ResultAsync<TValue = Unit, TError = string> {
385415
);
386416
}
387417

388-
tap(action: ActionOfT<TValue>): ResultAsync<TValue, TError>;
418+
/**
419+
*
420+
* @param action
421+
*/
389422
tap(
390423
asyncAction: FunctionOfTtoK<TValue, Promise<void>>
391424
): ResultAsync<TValue, TError>;
392425
tap<TOtherValue>(
393426
asyncAction: FunctionOfTtoK<TValue, ResultAsync<TOtherValue, TError>>
394427
): ResultAsync<TValue, TError>;
428+
tap(action: ActionOfT<TValue>): ResultAsync<TValue, TError>;
395429
tap<TOtherValue>(
396430
action:
397431
| ActionOfT<TValue>
@@ -421,21 +455,29 @@ export class ResultAsync<TValue = Unit, TError = string> {
421455
);
422456
}
423457

458+
/**
459+
*
460+
* @param conditionOrPredicate
461+
* @param action
462+
* @returns
463+
*/
424464
tapIf(
425465
conditionOrPredicate: boolean | PredicateOfT<TValue>,
426466
action: ActionOfT<TValue>
427467
): ResultAsync<TValue, TError> {
428468
return new ResultAsync(
429469
this.value.then((r) => {
430-
if (isFunction(conditionOrPredicate)) {
431-
return r.tapIf(conditionOrPredicate, action);
432-
}
433-
434-
return r.tapIf(conditionOrPredicate, action);
470+
return isFunction(conditionOrPredicate)
471+
? r.tapIf(conditionOrPredicate, action)
472+
: r.tapIf(conditionOrPredicate, action);
435473
})
436474
);
437475
}
438476

477+
/**
478+
*
479+
* @param matcher
480+
*/
439481
match<TNewValue>(
440482
matcher: ResultMatcher<TValue, TError, TNewValue>
441483
): Promise<Some<TNewValue>>;
@@ -448,15 +490,20 @@ export class ResultAsync<TValue = Unit, TError = string> {
448490
return this.value.then((r) => r.match(matcher));
449491
}
450492

493+
/**
494+
*
495+
* @param projection
496+
* @returns
497+
*/
451498
finally<TNewValue>(
452499
projection: FunctionOfTtoK<Result<TValue, TError>, Some<TNewValue>>
453500
): Promise<Some<TNewValue>> {
454501
return this.value.then((r) => r.finally(projection));
455502
}
456503

457-
onFailure(action: ActionOfT<TError>): ResultAsync<TValue, TError>;
458-
onFailure(action: AsyncActionOfT<TError>): ResultAsync<TValue, TError>;
459-
onFailure(
504+
tapFailure(action: ActionOfT<TError>): ResultAsync<TValue, TError>;
505+
tapFailure(action: AsyncActionOfT<TError>): ResultAsync<TValue, TError>;
506+
tapFailure(
460507
action: ActionOfT<TError> | AsyncActionOfT<TError>
461508
): ResultAsync<TValue, TError> {
462509
return new ResultAsync(

test/result/bindAsync.spec.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,6 @@ describe('Result', () => {
2929
expect(result).toFailWith(error);
3030
expect(wasCalled).toBe(false);
3131
});
32-
33-
test('will call the projection function when the original Result succeeds and convert a rejected Promise to a failed Result', async () => {
34-
const sut = Result.success(1);
35-
36-
const result = await sut
37-
.bindAsync(
38-
(_number) => Promise.reject('reject'),
39-
(e) => (typeof e === 'string' ? e : 'caught')
40-
)
41-
.toPromise();
42-
43-
expect(result).toFailWith('reject');
44-
});
4532
});
4633

4734
describe('ResultAsync', () => {

test/result/mapAsync.spec.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,5 @@ describe('Result', () => {
2727
expect(result).toFailWith(error);
2828
expect(wasCalled).toBe(false);
2929
});
30-
31-
test('will execute the mapping with a failed Result and convert a rejected Promise to a failed Result', async () => {
32-
const sut = Result.success(1);
33-
34-
const result = await sut
35-
.mapAsync(
36-
(_num) => {
37-
return Promise.reject('reject');
38-
},
39-
(e) => (typeof e === 'string' ? e : 'caught')
40-
)
41-
.toPromise();
42-
43-
expect(result).toFailWith('reject');
44-
});
4530
});
4631
});

0 commit comments

Comments
 (0)