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

Add non-spread overload for Result.all #86

Closed
wants to merge 1 commit into from
Closed
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
10 changes: 5 additions & 5 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -2,11 +2,6 @@ module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testRegex: '/test/.*.test.ts',
globals: {
'ts-jest': {
tsconfig: 'test/tsconfig.json',
},
},
collectCoverageFrom: ['src/**/*.ts'],
collectCoverage: true,
coverageThreshold: {
@@ -17,4 +12,9 @@ module.exports = {
statements: 100,
},
},
transform: {
'^.*\.ts$': ['ts-jest', {
tsconfig: 'test/tsconfig.json'
}]
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This silences the warnings that global ts-jest configuration is deprecated

};
12,713 changes: 7,531 additions & 5,182 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -22,11 +22,11 @@
"@types/jest": "^26.0.22",
"conditional-type-checks": "^1.0.5",
"copyfiles": "^2.4.1",
"jest": "^26.6.3",
"jest": "^29.7.0",
"prettier": "^2.2.1",
"rxjs": "^6.6.7",
"ts-jest": "^26.5.4",
"tslib": "^2.1.0",
"typescript": "^4.2"
"ts-jest": "^29.1.2",
"tslib": "^2.6.2",
"typescript": "^5.4"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bumping to typescript 5.X allows the use of const type params.

}
}
2 changes: 1 addition & 1 deletion src/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ts-results",
"version": "3.3.0",
"version": "3.4.0",
"description": "A typescript implementation of Rust's Result and Option objects.",
"main": "index.js",
"module": "./esm/index.js",
27 changes: 26 additions & 1 deletion src/result.ts
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ interface BaseResult<T, E> extends Iterable<T extends Iterable<infer U> ? U : ne
* @param msg the message to throw if Ok value.
*/
expectErr(msg: string): T;

/**
* Returns the contained `Ok` value.
* Because this function may throw, its use is generally discouraged.
@@ -296,9 +296,19 @@ export namespace Result {
* Parse a set of `Result`s, returning an array of all `Ok` values.
* Short circuits with the first `Err` found, if any
*/
export function all<const T extends Result<any, any>[]>(results: T): Result<ResultOkTypes<T>, ResultErrTypes<T>[number]>
export function all<T extends Result<any, any>[]>(
...results: T
): Result<ResultOkTypes<T>, ResultErrTypes<T>[number]>
export function all<T extends Result<any, any>[]>(
arg0: Head<T> | T, ...argN: Tail<T>
): Result<ResultOkTypes<T>, ResultErrTypes<T>[number]> {
const results = arg0 === undefined
? []
: Array.isArray(arg0)
? arg0 as T
: [arg0, ...argN] as T;

const okResult = [];
for (let result of results) {
if (result.ok) {
@@ -315,9 +325,19 @@ export namespace Result {
* Parse a set of `Result`s, short-circuits when an input value is `Ok`.
* If no `Ok` is found, returns an `Err` containing the collected error values
*/
export function any<const T extends Result<any, any>[]>(results: T): Result<ResultOkTypes<T>[number], ResultErrTypes<T>>
export function any<T extends Result<any, any>[]>(
...results: T
): Result<ResultOkTypes<T>[number], ResultErrTypes<T>>
export function any<T extends Result<any, any>[]>(
arg0: Head<T> | T, ...argN: Tail<T>
): Result<ResultOkTypes<T>[number], ResultErrTypes<T>> {
const results = arg0 === undefined
? []
: Array.isArray(arg0)
? arg0 as T
: [arg0, ...argN] as T;

const errResult = [];

// short-circuits
@@ -363,3 +383,8 @@ export namespace Result {
return val instanceof Err || val instanceof Ok;
}
}

// Utility types
type Head<T extends any[]> = T extends [any, ...infer R] ?
T extends [...infer F, ...R] ? F : never : never
type Tail<T extends any[]> = T extends [any, ...infer R] ? R : never
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These could likely be removed since the arrays I'm parsing above are typed as any[]. I could just as easily type the arguments as arg0: T[0] | T, argN: ...T but using these types are technically truer to what's going on.

70 changes: 54 additions & 16 deletions test/result.test.ts
Original file line number Diff line number Diff line change
@@ -110,20 +110,39 @@ test('Result.all', () => {
expect(all0).toMatchResult(Ok([]));
eq<typeof all0, Result<[], never>>(true);

const all0_array = Result.all([]);
expect(all0_array).toMatchResult(Ok([]));
eq<typeof all0_array, Result<[], never>>(true);

const all1 = Result.all(ok0, ok1);
expect(all1).toMatchResult(Ok([3, true]));
eq<typeof all1, Result<[number, boolean], never>>(true);

const all3 = Result.all(err0, err1);
expect(all3).toMatchResult(Err(err0.val));
eq<typeof all3, Result<[never, never], symbol | Error>>(true);
const all1Array = Result.all([ok0, ok1]);
expect(all1Array).toMatchResult(Ok([3, true]));
eq<typeof all1Array, Result<[number, boolean], never>>(true);

const all2 = Result.all(err0, err1);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected the naming indexes being off for all2 and onward

expect(all2).toMatchResult(Err(err0.val));
eq<typeof all2, Result<[never, never], symbol | Error>>(true);

const all2Array = Result.all([err0, err1]);
expect(all2Array).toMatchResult(Err(err0.val));
eq<typeof all2Array, Result<[never, never], symbol | Error>>(true);

const all3 = Result.all(...([] as Result<string, number>[]));
eq<typeof all3, Result<string[], number>>(true);

const all3Array = Result.all([] as Result<string, number>[]);
eq<typeof all3Array, Result<string[], number>>(true);

const all4 = Result.all(...([] as Result<string, number>[]));
eq<typeof all4, Result<string[], number>>(true);
const all4 = Result.all(ok0, ok1, ok2, err2);
expect(all4).toMatchResult(Err(9));
eq<typeof all4, Result<[number, boolean, 8, boolean], boolean | 9>>(true);

const all5 = Result.all(ok0, ok1, ok2, err2);
expect(all5).toMatchResult(Err(9));
eq<typeof all5, Result<[number, boolean, 8, boolean], boolean | 9>>(true);
const all4Array = Result.all([ok0, ok1, ok2, err2]);
expect(all4Array).toMatchResult(Err(9));
eq<typeof all4Array, Result<[number, boolean, 8, boolean], boolean | 9>>(true);
});

test('Result.any', () => {
@@ -138,20 +157,39 @@ test('Result.any', () => {
expect(any0).toMatchResult(Err([]));
eq<typeof any0, Result<never, []>>(true);

const any0Array = Result.any();
expect(any0Array).toMatchResult(Err([]));
eq<typeof any0Array, Result<never, []>>(true);

const any1 = Result.any(ok0, ok1);
expect(any1).toMatchResult(Ok(3));
eq<typeof any1, Result<number | boolean, [never, never]>>(true);

const any3 = Result.any(err0, err1);
expect(any3).toMatchResult(Err([err0.val, err1.val]));
eq<typeof any3, Result<never, [symbol, Error]>>(true);
const any1Array = Result.any([ok0, ok1]);
expect(any1Array).toMatchResult(Ok(3));
eq<typeof any1Array, Result<number | boolean, [never, never]>>(true);

const any2 = Result.any(err0, err1);
expect(any2).toMatchResult(Err([err0.val, err1.val]));
eq<typeof any2, Result<never, [symbol, Error]>>(true);

const any2Array = Result.any([err0, err1]);
expect(any2Array).toMatchResult(Err([err0.val, err1.val]));
eq<typeof any2Array, Result<never, [symbol, Error]>>(true);

const any3 = Result.any(...([] as Result<string, number>[]));
eq<typeof any3, Result<string, number[]>>(true);

const any3Array = Result.any([] as Result<string, number>[]);
eq<typeof any3Array, Result<string, number[]>>(true);

const any4 = Result.any(...([] as Result<string, number>[]));
eq<typeof any4, Result<string, number[]>>(true);
const any4 = Result.any(err0, err1, err2, ok2);
expect(any4).toMatchResult(Ok(8));
eq<typeof any4, Result<boolean | 8, [symbol, Error, 9, boolean]>>(true);

const any5 = Result.any(err0, err1, err2, ok2);
expect(any5).toMatchResult(Ok(8));
eq<typeof any5, Result<boolean | 8, [symbol, Error, 9, boolean]>>(true);
const any4Array = Result.any([err0, err1, err2, ok2]);
expect(any4Array).toMatchResult(Ok(8));
eq<typeof any4Array, Result<boolean | 8, [symbol, Error, 9, boolean]>>(true);
});

test('Result.wrap', () => {