diff --git a/src/interfaces/maybe.interface.ts b/src/interfaces/maybe.interface.ts index 933bae2..d540152 100644 --- a/src/interfaces/maybe.interface.ts +++ b/src/interfaces/maybe.interface.ts @@ -61,4 +61,6 @@ export interface IMaybe extends IMonad { // tslint:disable-next-line:readonly-array of(x?: T, ...args: any[]): IMaybe + + filter(fn: (t: T) => boolean): IMaybe } \ No newline at end of file diff --git a/src/monads/maybe.ts b/src/monads/maybe.ts index daa7f85..6489299 100644 --- a/src/monads/maybe.ts +++ b/src/monads/maybe.ts @@ -5,11 +5,16 @@ export function maybe(value?: T): IMaybe> { of: maybe, valueOr: (val: NonNullable) => value === null || value === undefined ? val : value as NonNullable, valueOrCompute: (f: () => NonNullable) => value === null || value === undefined ? f() : value as NonNullable, - tap: (obj: Partial>) => value === null || value === undefined ? obj.none && obj.none() : obj.some && obj.some(value as NonNullable), + tap: (obj: Partial>) => value === null || value === undefined ? obj.none && obj.none() : obj.some && obj.some(value as NonNullable), tapNone: (f: () => void) => (value === null || value === undefined) && f(), tapSome: (f: (val: NonNullable) => void) => value !== null && value !== undefined && f(value as NonNullable), - match: (pattern: IMaybePattern) => value === null || value === undefined ? pattern.none() : pattern.some(value as NonNullable), + match: (pattern: IMaybePattern) => value === null || value === undefined ? pattern.none() : pattern.some(value as NonNullable), map: (f: (t: NonNullable) => R) => value === null || value === undefined ? maybe() : maybe(f(value as NonNullable)), - flatMap: (f: (d: NonNullable) => IMaybe) => value === null || value === undefined ? maybe() : f(value as NonNullable) + flatMap: (f: (d: NonNullable) => IMaybe) => value === null || value === undefined ? maybe() : f(value as NonNullable), + filter: (fn: (d: NonNullable) => boolean) => value === null || value === undefined + ? maybe() + : fn(value as NonNullable) + ? maybe(value as NonNullable) + : maybe() } } diff --git a/test/monads/maybe.spec.ts b/test/monads/maybe.spec.ts index 90de6c8..4903c27 100644 --- a/test/monads/maybe.spec.ts +++ b/test/monads/maybe.spec.ts @@ -290,5 +290,43 @@ describe('Maybe', () => { maybe(sut).tapSome(() => expect(1).toEqual(1)) }) }) + + describe('when filtering', () => { + it('pass value through if predicate is resolves true', () => { + const thing: { readonly isGreen: boolean } | undefined = { isGreen: true } + + expect.assertions(1) + maybe(thing) + .filter(a => a.isGreen === true) + .tap({ + some: _thing => expect(_thing).toEqual(thing), + none: () => expect(1).toEqual(1) + }) + }) + + it('should not pass value through if predicate is resolves false', () => { + const thing: { readonly isGreen: boolean } | undefined = { isGreen: false } + + expect.assertions(1) + maybe(thing) + .filter(a => a.isGreen === true) + .tap({ + some: _thing => expect(true).toBe(false), + none: () => expect(1).toEqual(1) + }) + }) + + it('should handle undefineds correctly', () => { + const thing = undefined as { readonly isGreen: boolean } | undefined + + expect.assertions(1) + maybe(thing) + .filter(a => a.isGreen === true) + .tap({ + some: _thing => expect(true).toBe(false), + none: () => expect(1).toEqual(1) + }) + }) + }) })