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

feat: add tap methods to Result #188

Merged
merged 4 commits into from
Nov 5, 2022
Merged
Show file tree
Hide file tree
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
15 changes: 15 additions & 0 deletions src/result/result.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@ export interface IResult<T, E> {
mapFail<M>(fn: (err: E) => M): IResult<T, M>
flatMap<M>(fn: (val: T) => IResult<M, E>): IResult<M, E>

/**
* Execute functions with side-effects.
*/
tap(val: Partial<IResultMatchPattern<T, E, void>>): void

/**
* Execute a function with side-effects when maybe is a Fail.
*/
tapFail(f: (val: E) => void): void

/**
* Execute a function with side-effects when maybe is an Ok.
*/
tapOk(f: (val: T) => void): void

/**
* Convert Ok result into Fail using projected value from Ok
*/
Expand Down
54 changes: 54 additions & 0 deletions src/result/result.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,58 @@ describe('result', () => {
expect(sut.unwrapFail().message).toEqual('error msg')
})
})

describe('tap', () => {
it('should tap.ok', done => {
const sut = ok(1)

sut.tap({
ok: num => {
expect(num).toEqual(1)
done()
},
fail: done
})
})

it('should tap.ok', done => {
const sut = fail<number, string>('failed')

sut.tap({
fail: str => {
expect(str).toEqual('failed')
done()
},
ok: done
})
})

it('should tapOk', done => {
const sut = ok<number, string>(1)

sut.tapOk(num => {
expect(num).toEqual(1)
done()
})

sut.tapFail(() => {
expect(true).toBeFalsy()
done()
})
})

it('should tapFail', done => {
const sut = fail<number, string>('failed')

sut.tapFail(err => {
expect(err).toEqual('failed')
done()
})

sut.tapOk(() => {
expect(true).toBeFalsy()
done()
})
})
})
})
25 changes: 23 additions & 2 deletions src/result/result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@ import { IResultMatchPattern, IResult } from './result.interface'

export abstract class Result<TOk, TFail> implements IResult<TOk, TFail> {
public static ok<TOk, TFail>(value: TOk): IResult<TOk, TFail> {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return new OkResult<TOk, TFail>(value)
}

public static fail<TOk, TFail>(value: TFail): IResult<TOk, TFail> {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return new FailResult<TOk, TFail>(value)
}

Expand All @@ -25,6 +23,9 @@ export abstract class Result<TOk, TFail> implements IResult<TOk, TFail> {
abstract flatMap<M>(fn: (val: TOk) => IResult<M, TFail>): IResult<M, TFail>
abstract toFailWhenOk(fn: (val: TOk) => TFail): IResult<TOk, TFail>
abstract toFailWhenOkFrom(val: TFail): IResult<TOk, TFail>
abstract tap(val: IResultMatchPattern<TOk, TFail, void>): void
abstract tapOk(f: (val: TOk) => void): void
abstract tapFail(f: (val: TFail) => void): void
}

export class OkResult<TOk, TFail> extends Result<TOk, TFail> {
Expand Down Expand Up @@ -83,6 +84,16 @@ export class OkResult<TOk, TFail> extends Result<TOk, TFail> {
toFailWhenOkFrom(val: TFail): IResult<TOk, TFail> {
return Result.fail(val)
}

tap(val: Partial<IResultMatchPattern<TOk, TFail, void>>): void {
typeof val.ok === 'function' && val.ok(this.successValue)
}

tapOk(fn: (val: TOk) => void): void {
fn(this.successValue)
}

tapFail(): void { }
}

export class FailResult<TOk, TFail> extends Result<TOk, TFail> implements IResult<TOk, TFail> {
Expand Down Expand Up @@ -141,4 +152,14 @@ export class FailResult<TOk, TFail> extends Result<TOk, TFail> implements IResul
toFailWhenOkFrom(val: TFail): IResult<TOk, TFail> {
return Result.fail(val)
}

tap(val: Partial<IResultMatchPattern<TOk, TFail, void>>): void {
typeof val.fail === 'function' && val.fail(this.failureValue)
}

tapOk(): void { }

tapFail(fn: (val: TFail) => void): void {
fn(this.failureValue)
}
}