UNPKG

typescript-nullable

Version:

A TypeScript Nullable<T> Type and Monad Compliant Utility Functions

175 lines (154 loc) 5.33 kB
import { add, compose, curry, toUpper, } from 'ramda' import { Nullable } from '.' describe('the Nullable module', () => { const name: string = 'noob noob' describe('isNone', () => { it('determines if a particular Nullable is None', () => { expect(Nullable.isNone(null)).toBe(true) expect(Nullable.isNone('hi')).toBe(false) }) it('provides a typeguard', () => { const handleNullable = (someNullable: Nullable<string>): string => { if (!Nullable.isNone(someNullable)) { return someNullable } return 'value was undefined' } expect(handleNullable('oooh wee!')).toBe('oooh wee!') expect(handleNullable(null)).toBe('value was undefined') }) }) describe('isSome', () => { it('determines if a particular Nullable is a concrete value', () => { expect(Nullable.isSome(null)).toBe(false) expect(Nullable.isSome('hi')).toBe(true) }) it('provides a typeguard', () => { const handleNullable = (someNullable: Nullable<string>): string => { if (Nullable.isSome(someNullable)) { return someNullable } return 'value was undefined' } expect(handleNullable('oooh wee!')).toBe('oooh wee!') expect(handleNullable(null)).toBe('value was undefined') }) }) describe('Nullable.map', () => { describe('when given a None', () => { it('returns a None', () => { const result = Nullable.map(toUpper)(null) expect(result).toEqual(null) }) }) describe('when given a concrete value', () => { it('applies the provided function to the concrete value value', () => { const result = Nullable.map(toUpper, name) expect(result).toEqual(toUpper(name)) }) }) }) describe('Nullable.andThen', () => { const safeDivide = curry((a: number, b: number): Nullable<number> => { return a === 0 ? null : b / a }) describe('when we encounter a None in a composition chain', () => { it('gracefully handles the absence', () => { const result = compose( Nullable.andThen(safeDivide(3)), Nullable.andThen(safeDivide(0)), Nullable.andThen(safeDivide(4)), safeDivide(2), )(32) expect(result).toEqual(null) }) }) describe('when a composition chain works out according to plan', () => { it('returns our desired result', () => { const result = compose( Nullable.andThen(safeDivide(3)), Nullable.andThen(safeDivide(5)), Nullable.andThen(safeDivide(4)), safeDivide(2), )(32) expect(result).toEqual(32 / 2 / 4 / 5 / 3) }) }) }) describe('Nullable.withDefault', () => { describe('when given a default value and a None', () => { it('returns the default value', () => { const result = Nullable.withDefault(name)(null) expect(result).toBe(name) }) }) describe('when given a default value and a concrete value', () => { it('returns the concrete value value', () => { const result = Nullable.withDefault<string>('foo', name) expect(result).toBe(name) }) }) }) describe('Nullable.ap', () => { describe('when the applicative Nullable is None', () => { it('returns a None', () => { const result = Nullable.ap(name)(null) expect(result).toEqual(null) }) }) describe('when the target Nullable is None', () => { it('returns a None', () => { const result = Nullable.ap(null as Nullable<string>)(toUpper) expect(result).toEqual(null) }) }) describe('when both the applicative and target Nullables are Justs', () => { it('applies the wrapped function in the applicative Nullable to value in the target Nullable', () => { const result = Nullable.ap(name)(toUpper) expect(result).toEqual(toUpper(name)) }) }) describe('lifting functions', () => { const addThreeNumbers = (a: number) => (b: number) => (c: number) => a + b + c describe('when everything goes according to plan', () => { it('lifts a "regular" function into Nullable context and returns the correct value', () => { const result = compose( Nullable.ap(3), Nullable.ap(2), Nullable.ap(1), )(addThreeNumbers) expect(result).toBe(1 + 2 + 3) }) }) describe('when we exprience an absence', () => { it('lifts a "regular" function into Nullable context and returns null', () => { const result = compose( Nullable.ap(3), Nullable.ap(null as Nullable<number>), Nullable.ap(1), )(addThreeNumbers) expect(result).toBe(null) }) }) }) }) describe('Nullable.maybe', () => { describe('when given a None', () => { it('returns the default value', () => { expect(Nullable.maybe(7, add(83), null)).toBe(7) }) }) describe('when given a concrete value', () => { it('applies the provided function to the concrete value and returns the resulting return value', () => { expect(Nullable.maybe(7, add(83), 34)).toBe(83 + 34) }) }) }) })