Skip to content

Commit f8be2dc

Browse files
author
Erik
committed
added Result.forward()
1 parent 0722618 commit f8be2dc

File tree

3 files changed

+55
-1
lines changed

3 files changed

+55
-1
lines changed

README.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ The problem with this 'usual' try-catch approach is that:
3838
- it makes our code harder to reason about. We need to look at implementation details to discover what might go wrong.
3939
- it makes the control flow of our code harder to reason about, especially with multiple (nested) try-catch statements
4040

41-
Instead, we could express the outcome of code to be executed in the form of a Return-type. People using your code will be explicitly confronted with the fact that code potentially might fail, and will know upfront what kind of errors they can expect.
41+
Instead, we could express the outcome of code to be executed in the form of a Result-type. People using your code will be explicitly confronted with the fact that code potentially might fail, and will know upfront what kind of errors they can expect.
4242

4343
## Installation
4444

@@ -305,6 +305,36 @@ function doB(value: number): Result<ErrorB, string> {}
305305
const result = doA().map(value => doB(value)); // Result<ErrorA | ErrorB, string>
306306
```
307307

308+
#### Result.forward()
309+
310+
Creates and forwards a brand new Result out of the current error or value.
311+
This is useful if you want to return early after failure.
312+
313+
```ts
314+
class ErrorA extends Error {}
315+
class ErrorB extends Error {}
316+
317+
function doA(): Result<ErrorA, number> {}
318+
function doB(): Result<ErrorB, number> {}
319+
320+
function performAction(): Result<ErrorA | ErrorB, number> {
321+
const resultA = doA();
322+
if (resultA.isFailure()) {
323+
return resultA.forward();
324+
}
325+
326+
const resultB = doA();
327+
if (resultB.isFailure()) {
328+
return resultB.forward();
329+
}
330+
331+
// from here both 'a' and 'b' are valid values
332+
const [a, b] = [resultA.value, resultB.value];
333+
334+
return a + b;
335+
}
336+
```
337+
308338
## Rollbacks
309339

310340
There are cases where a series of operations are performed that need to be treated as a 'unit of work'. In other words: if the last operation fails, de preceding operations should also fail, despite the fact that those preceding operations succeeded on their own. In such cases you probably want some kind of recovering a.k.a. a rollback.

src/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,13 @@ class Ok<
702702
toString(): string {
703703
return `Result.Ok(${this.value})`;
704704
}
705+
706+
/**
707+
* **Creates and forwards a brand new Result out of the current error or value **
708+
*/
709+
forward(): Result<unknown, OkType, RollbackFn> {
710+
return Result.ok(this.value);
711+
}
705712
}
706713

707714
class Err<
@@ -727,4 +734,11 @@ class Err<
727734
toString(): string {
728735
return `Result.Error(${this.error})`;
729736
}
737+
738+
/**
739+
* **Creates and forwards a brand new Result out of the current error or value **
740+
*/
741+
forward(): Result<ErrorType, unknown, RollbackFn> {
742+
return Result.error(this.error);
743+
}
730744
}

src/test/index.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,5 +452,15 @@ describe("Result", () => {
452452
expect((resultError as any).error).toBe(ERROR);
453453
});
454454
});
455+
456+
describe("Result#forward", () => {
457+
it("forwards a error or value into a new Result", () => {
458+
const error = Result.error(ERROR);
459+
expect(error.forward().errorOrNull()).toBe(ERROR);
460+
461+
const success = Result.ok("success");
462+
expect(success.forward().getOrNull()).toBe("success");
463+
});
464+
});
455465
});
456466
});

0 commit comments

Comments
 (0)