Skip to content

Commit

Permalink
feat: add factory fromPromiseableResult
Browse files Browse the repository at this point in the history
  • Loading branch information
yifanwww committed Jun 15, 2024
1 parent 1c0db2b commit f72a7e5
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 22 deletions.
4 changes: 1 addition & 3 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ const naming = [

{ selector: 'enumMember', format: ['UPPER_CASE'], leadingUnderscore: 'forbid' },

{ selector: 'function', format: null, filter: { regex: '^(Ok|OkAsync|Err|ErrAsync)$', match: true } },
{ selector: 'function', format: ['camelCase'], leadingUnderscore: 'allow' },
{ selector: 'function', format: ['camelCase', 'PascalCase'], leadingUnderscore: 'allow' },

{ selector: 'method', modifiers: ['static'], format: null, filter: { regex: '^(Ok|Err)$', match: true } },
{ selector: 'method', modifiers: ['private'], format: ['camelCase'], leadingUnderscore: 'require' },
{ selector: 'method', modifiers: ['protected'], format: ['camelCase'], leadingUnderscore: 'require' },
{ selector: 'method', format: ['camelCase'], leadingUnderscore: 'forbid' },
Expand Down
65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Rust-like `Result` and `ResultAsync` for JavaScript.
- [Installation](#installation)
- [Usage](#usage)
- [About Rust `Option`](#about-rust-option)
- [Factories](#factories)
- [Methods Documentation](#methods-documentation)
- [Rust `Result` Methods](#rust-result-methods)
- [Synchronous Methods (`Result`)](#synchronous-methods-result)
Expand Down Expand Up @@ -121,6 +122,70 @@ This package doesn't implement Rust-like `Option`. Handling `undefined`/`null` i
[proposal-optional-chaining]: https://github.com/tc39/proposal-optional-chaining
[proposal-nullish-coalescing]: https://github.com/tc39/proposal-nullish-coalescing

## Factories
### `Ok`

Creates a `Result` that contains the success value.

Examples:

```ts
const result1 = Ok(1);
const result2 = Ok<number, string>(1);
const result3: Result<number, string> = Ok(1);
```

### `Err`

Creates a `Result` that contains the error value.

Examples:

```ts
const result1 = Err('Some error message');
const result2 = Err<number, string>('Some error message');
const result3: Result<number, string> = Err('Some error message');
```

### `OkAsync`

Creates a `ResultAsync` that contains the success value.

Examples:

```ts
const result1 = OkAsync(1);
const result2 = OkAsync<number, string>(1);
const result3: ResultAsync<number, string> = OkAsync(1);
```

### `ErrAsync`

Creates a `ResultAsync` that contains the error value.

Examples:

```ts
const result1 = ErrAsync('Some error message');
const result2 = ErrAsync<number, string>('Some error message');
const result3: ResultAsync<number, string> = ErrAsync('Some error message');
```

### `fromPromiseableResult`

Creates a `ResultAsync` from a promiseable `Result`.

Examples:

```ts
const result1 = fromPromiseableResult<number, string>(Ok(1));
const result2 = fromPromiseableResult<number, string>(Err('Some error message'));
const result3 = fromPromiseableResult<number, string>(Promise.resolve(Ok(1)));
const result4 = fromPromiseableResult<number, string>(Promise.resolve(Err('Some error message')));
const result5 = fromPromiseableResult<number, string>(OkAsync(1));
const result6 = fromPromiseableResult<number, string>(ErrAsync('Some error message'));
```

## Methods Documentation
### Rust `Result` Methods

Expand Down
2 changes: 2 additions & 0 deletions src/RustlikeResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ export class RustlikeResult<T, E> implements Result<T, E> {
/**
* Creates a `Result` that contains the success value.
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
static Ok<T, E = never>(value: T): Result<T, E> {
return new RustlikeResult<T, E>('ok', value);
}

/**
* Creates a `Result` that contains the error value.
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
static Err<E, T = never>(error: E): Result<T, E> {
return new RustlikeResult<T, E>('err', error);
}
Expand Down
16 changes: 9 additions & 7 deletions src/__tests__/factory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ describe(`Test fn \`${Ok.name}\``, () => {
it('should create `Ok` result', () => {
const result1 = Ok(1);
const result2 = Ok<number, string>(1);
const result3: Result<number, string> = Ok(2);
const result3: Result<number, string> = Ok(1);

expectResult(result1, { type: 'ok', value: 1, error: undefined });
expectResult(result2, { type: 'ok', value: 1, error: undefined });
expectResult(result3, { type: 'ok', value: 2, error: undefined });
const expected = { type: 'ok', value: 1, error: undefined } as const;
expectResult(result1, expected);
expectResult(result2, expected);
expectResult(result3, expected);
});
});

Expand All @@ -23,8 +24,9 @@ describe(`Test fn \`${Err.name}\``, () => {
const result2 = Err<number, string>('Some error message');
const result3: Result<number, string> = Err('Some error message');

expectResult(result1, { type: 'err', value: undefined, error: 'Some error message' });
expectResult(result2, { type: 'err', value: undefined, error: 'Some error message' });
expectResult(result3, { type: 'err', value: undefined, error: 'Some error message' });
const expected = { type: 'err', value: undefined, error: 'Some error message' } as const;
expectResult(result1, expected);
expectResult(result2, expected);
expectResult(result3, expected);
});
});
39 changes: 31 additions & 8 deletions src/__tests__/factoryAsync.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, it } from '@jest/globals';

import { ErrAsync, OkAsync } from '../factoryAsync';
import { Err, Ok } from '../factory';
import { ErrAsync, fromPromiseableResult, OkAsync } from '../factoryAsync';
import type { ResultAsync } from '../ResultAsync';

import { expectResultAsync } from './_helpers';
Expand All @@ -9,11 +10,12 @@ describe(`Test fn \`${OkAsync.name}\``, () => {
it('should create `OkAsync` result', async () => {
const result1 = OkAsync(1);
const result2 = OkAsync<number, string>(1);
const result3: ResultAsync<number, string> = OkAsync(2);
const result3: ResultAsync<number, string> = OkAsync(1);

await expectResultAsync(result1, { type: 'ok', value: 1, error: undefined });
await expectResultAsync(result2, { type: 'ok', value: 1, error: undefined });
await expectResultAsync(result3, { type: 'ok', value: 2, error: undefined });
const expected = { type: 'ok', value: 1, error: undefined } as const;
await expectResultAsync(result1, expected);
await expectResultAsync(result2, expected);
await expectResultAsync(result3, expected);
});
});

Expand All @@ -23,8 +25,29 @@ describe(`Test fn \`${ErrAsync.name}\``, () => {
const result2 = ErrAsync<number, string>('Some error message');
const result3: ResultAsync<number, string> = ErrAsync('Some error message');

await expectResultAsync(result1, { type: 'err', value: undefined, error: 'Some error message' });
await expectResultAsync(result2, { type: 'err', value: undefined, error: 'Some error message' });
await expectResultAsync(result3, { type: 'err', value: undefined, error: 'Some error message' });
const expected = { type: 'err', value: undefined, error: 'Some error message' } as const;
await expectResultAsync(result1, expected);
await expectResultAsync(result2, expected);
await expectResultAsync(result3, expected);
});
});

describe(`Test fn \`${fromPromiseableResult.name}\``, () => {
it('should create a `ResultAsync`', async () => {
const result1 = fromPromiseableResult<number, string>(Ok(1));
const result2 = fromPromiseableResult<number, string>(Err('Some error message'));
const result3 = fromPromiseableResult<number, string>(Promise.resolve(Ok(1)));
const result4 = fromPromiseableResult<number, string>(Promise.resolve(Err('Some error message')));
const result5 = fromPromiseableResult<number, string>(OkAsync(1));
const result6 = fromPromiseableResult<number, string>(ErrAsync('Some error message'));

const expectedOk = { type: 'ok', value: 1, error: undefined } as const;
const expectedErr = { type: 'err', value: undefined, error: 'Some error message' } as const;
await expectResultAsync(result1, expectedOk);
await expectResultAsync(result2, expectedErr);
await expectResultAsync(result3, expectedOk);
await expectResultAsync(result4, expectedErr);
await expectResultAsync(result5, expectedOk);
await expectResultAsync(result6, expectedErr);
});
});
2 changes: 1 addition & 1 deletion src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { RustlikeResult } from './RustlikeResult';
* ```ts
* const result1 = Ok(1);
* const result2 = Ok<number, string>(1);
* const result3: Result<number, string> = Ok(2);
* const result3: Result<number, string> = Ok(1);
* ```
*/
export function Ok<T, E = never>(value: T): Result<T, E> {
Expand Down
26 changes: 23 additions & 3 deletions src/factoryAsync.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import { Err, Ok } from './factory';
import type { Result } from './Result';
import type { ResultAsync } from './ResultAsync';
import { RustlikeResultAsync } from './RustlikeResultAsync';

/**
* Creates a `Result` that contains the success value.
* Creates a `ResultAsync` that contains the success value.
*
* Examples:
* ```ts
* const result1 = OkAsync(1);
* const result2 = OkAsync<number, string>(1);
* const result3: ResultAsync<number, string> = OkAsync(2);
* const result3: ResultAsync<number, string> = OkAsync(1);
* ```
*/
export function OkAsync<T, E = never>(value: T | Promise<T>): ResultAsync<T, E> {
return new RustlikeResultAsync(Promise.resolve(value).then(Ok));
}

/**
* Creates a `Result` that contains the error value.
* Creates a `ResultAsync` that contains the error value.
*
* Examples:
* ```ts
Expand All @@ -38,3 +39,22 @@ export function ErrAsync<T, E>(error: E | Promise<E>): ResultAsync<T, E>;
export function ErrAsync<T, E>(error: E | Promise<E>): ResultAsync<T, E> {
return new RustlikeResultAsync(Promise.resolve(error).then(Err<T, E>));
}

/**
* Creates a `ResultAsync` from a promiseable `Result`.
*
* Examples:
* ```ts
* const result1 = fromPromiseableResult<number, string>(Ok(1));
* const result2 = fromPromiseableResult<number, string>(Err('Some error message'));
* const result3 = fromPromiseableResult<number, string>(Promise.resolve(Ok(1)));
* const result4 = fromPromiseableResult<number, string>(Promise.resolve(Err('Some error message')));
* const result5 = fromPromiseableResult<number, string>(OkAsync(1));
* const result6 = fromPromiseableResult<number, string>(ErrAsync('Some error message'));
* ```
*/
export function fromPromiseableResult<T, E>(
result: Result<T, E> | Promise<Result<T, E>> | ResultAsync<T, E>,
): ResultAsync<T, E> {
return new RustlikeResultAsync(result);
}

0 comments on commit f72a7e5

Please sign in to comment.