diff --git a/README.md b/README.md index fa081db..1ccf6dd 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,18 @@ const now: Array = orig.map(x => parseInt(x)); none().map(v => console.log(v)) // does not print ``` +### tap +Like `map`, it calls a function with the current value, if there is one, but ignores any return value and the result is always the original Maybe. Intended for running side-effects, without changing the value. + +```typescript +some(1) + // If this was `.map`, then the result of this call would be None + .tap(x => console.log(`Original value is ${x}`)) + .map(x => x + 1) + .tap(x => console.log(`New value is ${x}`)) +``` + + ### flatMap FlatMap also accesses the contained value, but it expects that its "mapper" function returns a container of the same type. Imagine the conceptually equivalent array container: diff --git a/src/maybe.ts b/src/maybe.ts index 2d615a6..f79bf42 100644 --- a/src/maybe.ts +++ b/src/maybe.ts @@ -24,6 +24,7 @@ export default abstract class Maybe { abstract expect(msg?: string | Error): T; abstract caseOf(funcs: MatchType): Maybe; abstract map(f: (v: T) => Nullable): Maybe; + abstract tap(f: (v: T) => void): Maybe; abstract flatMap(f: (v: T) => Maybe): Maybe; abstract orElse(def: U | (() => U)): T | U; abstract or(other: Maybe | (() => Maybe)): Maybe; diff --git a/src/none.ts b/src/none.ts index 3f094f1..9646dfe 100644 --- a/src/none.ts +++ b/src/none.ts @@ -32,6 +32,10 @@ export default class None extends Maybe { return this as any; } + tap(): Maybe { + return this; + } + flatMap(): Maybe { return this as any; } diff --git a/src/some.ts b/src/some.ts index 4c0c89a..54ff9be 100644 --- a/src/some.ts +++ b/src/some.ts @@ -17,6 +17,12 @@ export default class Some extends Maybe { return maybe(f(this.value!)); } + tap(f: (v: T) => void): Maybe { + f(this.value!); + return this; + } + + flatMap(f: (v: T) => Maybe): Maybe { return f(this.value!); } diff --git a/tests/maybe.test.ts b/tests/maybe.test.ts index 5ec1a1d..9cec2cc 100644 --- a/tests/maybe.test.ts +++ b/tests/maybe.test.ts @@ -49,6 +49,29 @@ test('map - Gives back a maybe', checkInstance( none().map(noop), )); +// --- +// Tap +// --- + +test('Calls map function when contained value is non-nil', () => { + expect.assertions(2); + + const value = "i'm not nil"; + const definitely = some(value); + + definitely + .tap(v => expect(v).toBe(value)) + .tap(v => expect(v).toBe(value)); +}); + +test('Does not call tap function when contained value is nil', () => { + none().tap(raiseError); +}); + +test('tap - Gives back a maybe', checkInstance( + none().tap(noop), +)); + // -------- // Flat Map // --------