Skip to content

Commit f9a0cbc

Browse files
committed
adds overload to Result.gen and Result.genCatching for passing the this-context to the callback fn
1 parent 9f92c09 commit f9a0cbc

File tree

4 files changed

+117
-12
lines changed

4 files changed

+117
-12
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"private": false,
33
"name": "typescript-result",
4-
"version": "3.3.0-beta.1",
4+
"version": "3.3.0-beta.2",
55
"description": "A Result type inspired by Rust and Kotlin that leverages TypeScript's powerful type system to simplify error handling and make your code more readable and maintainable.",
66
"keywords": [
77
"result",

readme.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,6 +1455,7 @@ Executes the given `fn` (async) generator function and encapsulates the returned
14551455
This method is often used once as entry point to run a specific flow. The reason for this is that nested generator functions or calls to other functions that return results are supported.
14561456

14571457
#### Parameters
1458+
- `self` optional `this` context to bind the generator function to.
14581459
- `fn` (async) generator function to execute.
14591460

14601461
**returns** a new [`AsyncResult`](#asyncresult) or `Result` instance depending on the provided callback fn.
@@ -1470,6 +1471,22 @@ const result = Result.gen(async function* () {
14701471
}); // AsyncResult<string, NotFoundError | InvalidOrderStatusError>;
14711472
```
14721473

1474+
#### Example
1475+
With 'this' context
1476+
1477+
```ts
1478+
class MyClass {
1479+
someValue = 12;
1480+
1481+
someMethod() {
1482+
return Result.gen(this, function* () {
1483+
const otherValue = yield* Result.ok(8);
1484+
return `The sum is ${this.someValue + otherValue}`;
1485+
});
1486+
}
1487+
}
1488+
```
1489+
14731490
### Result.genCatching()
14741491

14751492
Similar to [`Result.gen()`](#resultgen) this method transforms the given generator function into a `Result` or [`AsyncResult`](#asyncresult) depending on whether the generator function contains async operations or not.

src/result.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,23 @@ describe("Result", () => {
10971097
const result = await asyncResult;
10981098
expect(result).toEqual(Result.ok(10));
10991099
});
1100+
1101+
it("allows to to pass the 'this' context", () => {
1102+
class MyClass {
1103+
constructor(public someValue: number) {}
1104+
1105+
methodA() {
1106+
return Result.gen(this, function* () {
1107+
return this.someValue;
1108+
});
1109+
}
1110+
}
1111+
1112+
const result = new MyClass(42).methodA();
1113+
expectTypeOf(result).toEqualTypeOf<Result<number, never>>();
1114+
Result.assertOk(result);
1115+
expect(result.value).toBe(42);
1116+
});
11001117
});
11011118

11021119
describe("Result.genCatching", () => {
@@ -1219,6 +1236,23 @@ describe("Result", () => {
12191236
Result.assertError(result);
12201237
expect(result.error).toEqual(new Error("Boom!"));
12211238
});
1239+
1240+
it("allows to to pass the 'this' context", () => {
1241+
class MyClass {
1242+
constructor(public someValue: number) {}
1243+
1244+
methodA() {
1245+
return Result.genCatching(this, function* () {
1246+
return this.someValue;
1247+
});
1248+
}
1249+
}
1250+
1251+
const result = new MyClass(42).methodA();
1252+
expectTypeOf(result).toEqualTypeOf<Result<number, Error>>();
1253+
Result.assertOk(result);
1254+
expect(result.value).toBe(42);
1255+
});
12221256
});
12231257

12241258
describe("instance methods and getters", () => {

src/result.ts

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1987,6 +1987,7 @@ export class Result<Value, Err> {
19871987
* Executes the given {@linkcode fn} (async) generator function and encapsulates the returned value or error as a Result.
19881988
* This method is often used once as entry point to run a specific flow. The reason for this is that nested generator functions or calls to other functions that return results are supported.
19891989
*
1990+
* @param self optional `this` context to bind the generator function to.
19901991
* @param fn generator function with code to execute. Can be synchronous or asynchronous.
19911992
* @returns a new {@linkcode Result} or {@linkcode AsyncResult} instance depending on the provided callback fn.
19921993
*
@@ -2001,14 +2002,43 @@ export class Result<Value, Err> {
20012002
* }); // AsyncResult<string, NotFoundError | InvalidOrderStatusError>;
20022003
* ```
20032004
*
2005+
* @example
2006+
* this context
2007+
* ```ts
2008+
* class MyClass {
2009+
* someValue = 12;
2010+
*
2011+
* someMethod() {
2012+
* return Result.gen(this, function* () {
2013+
* const otherValue = yield* Result.ok(8);
2014+
* return `The sum is ${this.someValue + otherValue}`;
2015+
* });
2016+
* }
2017+
* }
2018+
* ```
20042019
*/
2005-
static gen<T extends Generator | AsyncGenerator>(fn: () => T) {
2006-
const it = fn();
2007-
return Result.handleGenerator(it) as IfGeneratorAsync<
2008-
T,
2009-
AsyncResult<InferGeneratorReturn<T>, InferGeneratorError<T>>,
2010-
Result<InferGeneratorReturn<T>, InferGeneratorError<T>>
2011-
>;
2020+
static gen<T extends Generator | AsyncGenerator>(
2021+
fn: () => T,
2022+
): IfGeneratorAsync<
2023+
T,
2024+
AsyncResult<InferGeneratorReturn<T>, InferGeneratorError<T>>,
2025+
Result<InferGeneratorReturn<T>, InferGeneratorError<T>>
2026+
>;
2027+
static gen<T extends Generator | AsyncGenerator, This>(
2028+
self: This,
2029+
fn: (this: This) => T,
2030+
): IfGeneratorAsync<
2031+
T,
2032+
AsyncResult<InferGeneratorReturn<T>, InferGeneratorError<T>>,
2033+
Result<InferGeneratorReturn<T>, InferGeneratorError<T>>
2034+
>;
2035+
static gen<T extends Generator | AsyncGenerator>(
2036+
selfOrFn: unknown,
2037+
fn?: () => T,
2038+
) {
2039+
const it =
2040+
typeof selfOrFn === "function" ? selfOrFn() : fn?.apply(selfOrFn);
2041+
return Result.handleGenerator(it);
20122042
}
20132043

20142044
/**
@@ -2026,20 +2056,44 @@ export class Result<Value, Err> {
20262056
T,
20272057
AsyncResult<InferGeneratorReturn<T>, InferGeneratorError<T> | ErrorType>,
20282058
Result<InferGeneratorReturn<T>, InferGeneratorError<T> | ErrorType>
2029-
> {
2059+
>;
2060+
static genCatching<
2061+
T extends Generator | AsyncGenerator,
2062+
This,
2063+
ErrorType = NativeError,
2064+
>(
2065+
self: This,
2066+
fn: (this: This) => T,
2067+
transformError?: (error: unknown) => ErrorType,
2068+
): IfGeneratorAsync<
2069+
T,
2070+
AsyncResult<InferGeneratorReturn<T>, InferGeneratorError<T> | ErrorType>,
2071+
Result<InferGeneratorReturn<T>, InferGeneratorError<T> | ErrorType>
2072+
>;
2073+
static genCatching(
2074+
selfOrFn: unknown,
2075+
transformValueOrError?: Function,
2076+
transformError?: Function,
2077+
) {
2078+
const self = typeof selfOrFn === "function" ? undefined : selfOrFn;
2079+
const tValue =
2080+
typeof selfOrFn === "function" ? selfOrFn : transformValueOrError!;
2081+
const tError =
2082+
typeof selfOrFn === "function" ? transformValueOrError : transformError;
2083+
20302084
try {
2031-
const it = fn();
2085+
const it = self ? tValue.apply(selfOrFn) : tValue();
20322086
const result = Result.handleGenerator(it);
20332087

20342088
if (Result.isAsyncResult(result)) {
20352089
return result.catch((error) =>
2036-
AsyncResult.error(transformError?.(error) ?? error),
2090+
AsyncResult.error(tError?.(error) ?? error),
20372091
) as any;
20382092
}
20392093

20402094
return result as any;
20412095
} catch (error: unknown) {
2042-
return Result.error(transformError?.(error) ?? error) as any;
2096+
return Result.error(tError?.(error) ?? error) as any;
20432097
}
20442098
}
20452099

0 commit comments

Comments
 (0)