Skip to content

Commit 296acc1

Browse files
feat(maybe): introduce flatMapAuto (#68)
1 parent 750510c commit 296acc1

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

src/interfaces/maybe.interface.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ export interface IMaybe<T> extends IMonad<T> {
7373
*/
7474
flatMap<R>(f: (t: T) => IMaybe<R>): IMaybe<R>
7575

76+
/**
77+
* Combine multiple Maybe, automatically wrapping predicate
78+
*/
79+
flatMapAuto<R>(f: (t: T) => R): IMaybe<NonNullable<R>>
80+
7681
/**
7782
* Apply a predicate which if met, continues the Maybe chain,
7883
* otherwise return an empty Maybe

src/monads/maybe.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ const tapSome = <T>(value?: T) => (fn: (val: NonNullable<T>) => void) => isNotEm
1212
const match = <T>(value?: T) => <R>(pattern: IMaybePattern<T, R>) => isEmpty(value) ? pattern.none() : pattern.some(value as NonNullable<T>)
1313
const map = <T>(value?: T) => <R>(fn: (t: NonNullable<T>) => R) => isEmpty(value) ? maybe<R>() : maybe<R>(fn(value as NonNullable<T>))
1414
const flatMap = <T>(value?: T) => <R>(fn: (d: NonNullable<T>) => IMaybe<R>) => isEmpty(value) ? maybe<R>() : fn(value as NonNullable<T>)
15+
const flatMapAuto = <T>(value?: T) => <R>(fn: (d: NonNullable<T>) => R) => isEmpty(value) ? maybe<R>() : maybe<R>(fn(value as NonNullable<T>))
16+
1517
const filter = <T>(value?: T) =>
1618
(fn: (d: NonNullable<T>) => boolean) =>
1719
isEmpty(value)
@@ -34,6 +36,7 @@ export const maybe = <T>(value?: T): IMaybe<NonNullable<T>> => {
3436
match: match(value),
3537
map: map(value),
3638
flatMap: flatMap(value),
39+
flatMapAuto: flatMapAuto(value),
3740
filter: filter(value)
3841
}
3942
}

test/monads/maybe.spec.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { maybe } from "../../src"
1+
import { maybe } from '../../src'
22

33
describe('Maybe', () => {
44
describe('when returning a value by default', () => {
@@ -373,4 +373,42 @@ describe('Maybe', () => {
373373
expect(maybeThing).toEqual(['actual input'])
374374
})
375375
})
376+
377+
describe('flatMapAuto', () => {
378+
it('should flatMapAuto', () => {
379+
const sut = {
380+
thing: undefined
381+
} as { readonly thing: string | undefined } | undefined
382+
383+
const maybeAString = maybe(sut)
384+
.flatMapAuto(a => a.thing)
385+
.valueOrUndefined()
386+
387+
expect(maybeAString).toBeUndefined()
388+
})
389+
390+
it('should flatMapAuto inner', () => {
391+
const sut = {
392+
thing: 'testval'
393+
} as { readonly thing: string | undefined } | undefined
394+
395+
const maybeAString = maybe(sut)
396+
.flatMapAuto(a => a.thing)
397+
.map(a => a + 1)
398+
.valueOrUndefined()
399+
400+
expect(maybeAString).toEqual('testval1')
401+
})
402+
403+
it('should flatMapAuto with intial input as empty', () => {
404+
const sut = undefined as { readonly thing: string | undefined } | undefined
405+
406+
const maybeAString = maybe(sut)
407+
.flatMapAuto(a => a.thing)
408+
.map(a => a + 1)
409+
.valueOrUndefined()
410+
411+
expect(maybeAString).toBeUndefined()
412+
})
413+
})
376414
})

0 commit comments

Comments
 (0)