Skip to content
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
12 changes: 6 additions & 6 deletions src/interfaces/maybe.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface IMaybePattern<TIn, TOut> {
/**
* Function to handle when a value exists.
*/
some(val: TIn): TOut
some(val: NonNullable<TIn>): TOut

/**
* Function to handle when a value is undefined.
Expand All @@ -22,12 +22,12 @@ export interface IMaybe<T> extends IMonad<T> {
/**
* Unwrap a Maybe with a default value
*/
valueOr(val: T): T
valueOr(val: NonNullable<T>): NonNullable<T>

/**
* Unwrap a Maybe with a default computed value
*/
valueOrCompute(f: () => T): T
valueOrCompute(f: () => NonNullable<T>): NonNullable<T>

/**
* Execute functions with side-effects.
Expand All @@ -42,7 +42,7 @@ export interface IMaybe<T> extends IMonad<T> {
/**
* Execute a function with side-effects when maybe is a some.
*/
tapSome(f: (val: T) => void): void
tapSome(f: (val: NonNullable<T>) => void): void

/**
* Unwrap and apply MaybePattern functions
Expand All @@ -52,12 +52,12 @@ export interface IMaybe<T> extends IMonad<T> {
/**
* Combine multiple maybe
*/
map<R>(f: (t: T) => R): IMaybe<R>
map<R>(f: (t: NonNullable<T>) => R): IMaybe<R>

/**
* Combine multiple maybe
*/
flatMap<R>(f: (t: T) => IMaybe<R>): IMaybe<R>
flatMap<R>(f: (t: NonNullable<T>) => IMaybe<R>): IMaybe<R>

// tslint:disable-next-line:readonly-array
of(x?: T, ...args: any[]): IMaybe<T>
Expand Down
14 changes: 7 additions & 7 deletions src/monads/maybe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { IMaybe, IMaybePattern } from "../interfaces"
export function maybe<T>(value?: T): IMaybe<T> {
return {
of: (x) => maybe(x),
valueOr: (val: T) => value === null || value === undefined ? val : value,
valueOrCompute: (f: () => T) => value === null || value === undefined ? f() : value,
tap: (obj: Partial<IMaybePattern<T, void>>) => value === null || value === undefined ? obj.none && obj.none() : obj.some && obj.some(value),
valueOr: (val: NonNullable<T>) => value === null || value === undefined ? val : value as NonNullable<T>,
valueOrCompute: (f: () => NonNullable<T>) => value === null || value === undefined ? f() : value as NonNullable<T>,
tap: (obj: Partial<IMaybePattern<T, void>>) => value === null || value === undefined ? obj.none && obj.none() : obj.some && obj.some(value as NonNullable<T>),
tapNone: (f: () => void) => (value === null || value === undefined) && f(),
tapSome: (f: (val: T) => void) => value !== null && value !== undefined && f(value),
match: <R>(pattern: IMaybePattern<T, R>) => value === null || value === undefined ? pattern.none() : pattern.some(value),
map: <R>(f: (t: T) => R) => value === null || value === undefined ? maybe<R>() : maybe<R>(f(value)),
flatMap: <R>(f: (d: T) => IMaybe<R>) => value === null || value === undefined ? maybe<R>() : f(value)
tapSome: (f: (val: NonNullable<T>) => void) => value !== null && value !== undefined && f(value as NonNullable<T>),
match: <R>(pattern: IMaybePattern<T, R>) => value === null || value === undefined ? pattern.none() : pattern.some(value as NonNullable<T>),
map: <R>(f: (t: NonNullable<T>) => R) => value === null || value === undefined ? maybe<R>() : maybe<R>(f(value as NonNullable<T>)),
flatMap: <R>(f: (d: NonNullable<T>) => IMaybe<R>) => value === null || value === undefined ? maybe<R>() : f(value as NonNullable<T>)
}
}
52 changes: 26 additions & 26 deletions test/monads/maybe.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,35 @@ import { maybe } from "../../src"
describe('Maybe', () => {
describe('when returning a value by default', () => {
it('should handle "none" case', () => {
const sut: string | undefined = undefined
const sut = undefined as string | undefined
const maybeAString = maybe(sut).valueOr('default output')

expect(maybeAString).toEqual('default output')
})

it('should handle "some" case', () => {
const sut: string | undefined = 'actual input'
const sut = 'actual input' as string | undefined
const maybeAString = maybe(sut).valueOr('default output')

expect(maybeAString).toEqual('actual input')
})

it('should handle "some" case when input is null', () => {
const sut: string | undefined | null = null
const sut = null as string | undefined | null
const maybeAString = maybe(sut).valueOr('default output')

expect(maybeAString).toEqual('default output')
})

it('should handle "some" case when input is ""', () => {
const sut: string | undefined | null = ''
const sut = '' as string | undefined | null
const maybeAString = maybe(sut).valueOr('fallback')

expect(maybeAString).toEqual('')
})

it('should handle "some" case when input is 0', () => {
const sut: number | undefined | null = 0
const sut = 0 as number | undefined | null
const maybeAString = maybe(sut).valueOr(10)

expect(maybeAString).toEqual(0)
Expand All @@ -40,7 +40,7 @@ describe('Maybe', () => {

describe('when returning a value by computation', () => {
it('should handle "none" case', () => {
const sut: string | undefined = undefined
const sut = undefined as string | undefined
const maybeAString = maybe(sut).valueOrCompute(() => 'default output')

expect(maybeAString).toEqual('default output')
Expand All @@ -54,21 +54,21 @@ describe('Maybe', () => {
})

it('should handle "some" case when input is null', () => {
const sut: string | undefined = null
const sut = null as string | null
const maybeAString = maybe(sut).valueOrCompute(() => 'fallback')

expect(maybeAString).toEqual('fallback')
})

it('should handle "some" case when input is ""', () => {
const sut: string | undefined = ''
const sut = '' as string | undefined
const maybeAString = maybe(sut).valueOrCompute(() => 'fallback')

expect(maybeAString).toEqual('')
})

it('should handle "some" case when input is 0', () => {
const sut: number | undefined = 0
const sut = 0 as number | undefined
const maybeAString = maybe(sut).valueOrCompute(() => 10)

expect(maybeAString).toEqual(0)
Expand All @@ -77,7 +77,7 @@ describe('Maybe', () => {

describe('when returning from a match operation', () => {
it('should handle "none" case', () => {
const sut: string | undefined = undefined
const sut = undefined as string | undefined
const maybeAMappedString = maybe(sut)
.match({
none: () => 'fallback',
Expand All @@ -88,7 +88,7 @@ describe('Maybe', () => {
})

it('should handle "some" case', () => {
const sut: string | undefined = 'existing value'
const sut = 'existing value' as string | undefined
const maybeAMappedString = maybe(sut)
.match({
none: () => 'fallback',
Expand All @@ -102,8 +102,8 @@ describe('Maybe', () => {
describe('when performing side-effect operations', () => {
it('should handle "none" case', () => {
// tslint:disable-next-line:no-let
let sideEffectStore: string
const sut: string | undefined = undefined
let sideEffectStore = ''
const sut = undefined as string | undefined

maybe(sut)
.tap({
Expand All @@ -118,8 +118,8 @@ describe('Maybe', () => {

it('should handle "some" case', () => {
// tslint:disable-next-line:no-let
let sideEffectStore: string
const sut: string | undefined = 'existing value'
let sideEffectStore = ''
const sut = 'existing value' as string | undefined

maybe(sut)
.tap({
Expand All @@ -139,7 +139,7 @@ describe('Maybe', () => {
}

it('should handle valid input', () => {
const sut: string | undefined = 'initial input'
const sut = 'initial input' as string | undefined

const maybeSomeString = maybe(sut)
.map(_str => getUserService<string>('initial input mapped'))
Expand All @@ -163,7 +163,7 @@ describe('Maybe', () => {
})

it('should handle undefined input', () => {
const sut: string | undefined = undefined
const sut = undefined as string | undefined

const maybeSomeString = maybe(sut)
.map(_str => getUserService<string>('initial input mapped'))
Expand All @@ -187,7 +187,7 @@ describe('Maybe', () => {
})

it('should handle input of 0', () => {
const sut: number | undefined = 0
const sut = 0 as number | undefined

const maybeSomeString = maybe(sut)
.map(_str => getUserService<string>('initial input mapped'))
Expand All @@ -211,7 +211,7 @@ describe('Maybe', () => {
})

it('should handle input of ""', () => {
const sut: string | undefined = ''
const sut = '' as string | undefined

const maybeSomeString = maybe(sut)
.map(_str => getUserService<string>('initial input mapped'))
Expand All @@ -237,8 +237,8 @@ describe('Maybe', () => {

describe('when flatMapping', () => {
it('should handle "none" case', () => {
const sut: string | undefined = undefined
const nsut: number | undefined = undefined
const sut = undefined as string | undefined
const nsut = undefined as number | undefined

const maybeSomeNumber = maybe(sut)
.flatMap(() => maybe(nsut))
Expand All @@ -248,8 +248,8 @@ describe('Maybe', () => {
})

it('should handle "some" case', () => {
const sut: string | undefined = 'initial'
const nsut: number | undefined = 20
const sut = 'initial' as string | undefined
const nsut = 20 as number | undefined

const maybeSomeNumber = maybe(sut)
.flatMap(() => maybe(nsut))
Expand All @@ -261,7 +261,7 @@ describe('Maybe', () => {

describe('when getting monadic unit', () => {
it('should get value', () => {
const sut: string | undefined = undefined
const sut = undefined as string | undefined

const maybeSomeNumber = maybe(sut)
.of('ok')
Expand All @@ -273,7 +273,7 @@ describe('Maybe', () => {

describe('when tapSome', () => {
it('should work', () => {
const sut: string | undefined = 'abc'
const sut = 'abc' as string | undefined

expect.assertions(1)
maybe(sut).tapSome(a => expect(a).toEqual('abc'))
Expand All @@ -283,7 +283,7 @@ describe('Maybe', () => {

describe('when tapNone', () => {
it('should work', () => {
const sut: string | undefined = undefined
const sut = undefined as string | undefined

expect.assertions(1)
maybe(sut).tapNone(() => expect(1).toEqual(1))
Expand Down
25 changes: 25 additions & 0 deletions test/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"lib": ["es2015", "dom"],
"isolatedModules": false,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"noImplicitAny": true,
"noImplicitUseStrict": false,
"noEmitHelpers": false,
"noEmit": true,
"noLib": false,
"noUnusedLocals": true,
"noEmitOnError": true,
"allowSyntheticDefaultImports": false,
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"strict": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"forceConsistentCasingInFileNames": true
}
}