forked from fossabot/ahana-fp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: 🎸 make Result more user friendly
Result is nicer to use when we stick to the language of succcess and error, so this commit provides that BREAKING CHANGE: 🧨 y ✅ Closes: 195
- Loading branch information
Showing
4 changed files
with
131 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import {expect, describe, test} from 'vitest'; | ||
|
||
import {Result} from '../src/Result'; | ||
import {Optional} from '../src/Optional'; | ||
|
||
describe('Result', () => { | ||
test('maps Optionals correctly (right)', async () => { | ||
const e = Result.error(new Error('Test')); | ||
e.mapRight((d) => Optional.of(d)).apply( | ||
() => { | ||
throw new Error('Wrong function called'); | ||
}, | ||
(f) => { | ||
expect(f).toBeInstanceOf(Error); | ||
} | ||
); | ||
}); | ||
test('maps Optionals correctly (left)', async () => { | ||
const e = Result.success(1); | ||
e.mapLeft((d) => Optional.of(d)).apply( | ||
(f) => { | ||
expect(f).toBe(1); | ||
}, | ||
() => { | ||
throw new Error('Wrong function called'); | ||
} | ||
); | ||
}); | ||
test('maps Optionals correctly (both)', async () => { | ||
expect( | ||
Result.success(1).map( | ||
(d) => Optional.of((d as number) * 2), | ||
(d) => Optional.of(0) | ||
) | ||
).toBe(2); | ||
expect( | ||
Result.error(new Error('Test')).map( | ||
(d) => Optional.of((d as number) * 2), | ||
(d) => Optional.of(0) | ||
) | ||
).toBe(0); | ||
}); | ||
|
||
describe('.isError', () => { | ||
test('returns true for right values', () => { | ||
const e = Result.error(new Error('Test')); | ||
expect(e.isError()).toBe(true); | ||
}); | ||
test('returns false for left values', () => { | ||
const e = Result.success('test'); | ||
expect(e.isError()).toBe(false); | ||
}); | ||
}); | ||
|
||
describe('.isSuccess', () => { | ||
test('returns true for left values', () => { | ||
const e = Result.success('test'); | ||
expect(e.isSuccess()).toBe(true); | ||
}); | ||
test('returns false for right values', () => { | ||
const e = Result.error(new Error('Test')); | ||
expect(e.isSuccess()).toBe(false); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,48 @@ | ||
import {Either} from './Either'; | ||
import {Optional} from './Optional'; | ||
|
||
/** | ||
* A Result is a value that represents either success or failure. It's a special case of an Either. | ||
*/ | ||
export class Result<T, E extends Error = Error> extends Either<E, T> {} | ||
export class Result<T, E extends Error = Error> extends Either<T, E> { | ||
private static fromEither<ET, EE extends Error = Error>(either: Either<ET, EE>) { | ||
const left: Optional<ET> = Optional.of(either.isLeft() ? either.getLeft() : null); | ||
const right: Optional<EE> = Optional.of(either.isRight() ? either.getRight() : null); | ||
|
||
return new Result<ET, EE>(left, right); | ||
} | ||
|
||
public static success<NT, NE extends Error = Error>( | ||
value: NT | Optional<NT> | ||
): Result<NT, NE> { | ||
return Result.fromEither(Either.left<NT, NE>(value)); | ||
} | ||
|
||
public static error<NT, NE extends Error = Error>(value: NE): Result<NT, NE> { | ||
return Result.fromEither(Either.right<NT, NE>(value)); | ||
} | ||
|
||
public isSuccess() { | ||
return this.isLeft(); | ||
} | ||
|
||
public isError() { | ||
return this.isRight(); | ||
} | ||
|
||
public mapSuccess(...args: Parameters<Either<T, E>['mapLeft']>) { | ||
return this.mapLeft(...args); | ||
} | ||
|
||
public proceedWithSuccess(...args: Parameters<Either<T, E>['proceedLeft']>) { | ||
return this.proceedLeft(...args); | ||
} | ||
|
||
public mapError(...args: Parameters<Either<T, E>['mapRight']>) { | ||
return this.mapRight(...args); | ||
} | ||
|
||
public proceedsWithError(...args: Parameters<Either<T, E>['proceedRight']>) { | ||
return this.proceedRight(...args); | ||
} | ||
} |