项目作者: mikechabot

项目描述 :
Minimize defensive coding. A JavaScript implementation of the Maybe monad.
高级语言: JavaScript
项目地址: git://github.com/mikechabot/maybe-baby.git
创建时间: 2016-12-19T16:35:03Z
项目社区:https://github.com/mikechabot/maybe-baby

开源协议:MIT License

下载


maybe-baby

2.x will be maintained, however, if possible for your repository, you should opt to use TypeScript’s optional chaining, which was introduced in 3.7


Minimize defensive coding. A JavaScript implementation of the Maybe monad.




npm version


build status


coverage status


dependency status


devDependency status


Install" class="reference-link">Install

  • npm install --save maybe-baby
  • yarn add maybe-baby

Getting Started" class="reference-link">Getting Started

What if we need the zipCode of the user below, which lives on the address object?

  1. const user = {
  2. email: 'foo@bar.com',
  3. address: null,
  4. name: {
  5. first: 'John',
  6. last: null,
  7. middle: null
  8. }
  9. };

Accessing it via dot notation will result in an error:

  1. const zipCode = user.address.zipCode; // Uncaught TypeError: Cannot read property 'zipCode' of undefined

Possible Solutions?

  1. Write some ugly null checks that don’t scale well:
  1. const getZipCode = (user) => {
  2. if (user !== null && user !== undefined) {
  3. if (user.address !== null && user.address !== undefined) {
  4. return user.address.zipCode
  5. }
  6. }
  7. }
  1. Use _.get() or something similar, but these libraries have large footprints, and most likely won’t be implementing the monadic structure.

  2. Wait for optional chaining to be approved in ECMA, or use babel-plugin-transform-optional-chaining.

  3. Use TypeScript’s optional chaining

A Better Solution?

  1. Use maybe-baby to minimize defensive coding:
  1. import Maybe from 'maybe-baby';
  2. // Use a function getter
  3. const getZipCode = (user) => Maybe.of(() => user.address.zipCode).join();

Now we can safely get the zipCode without worrying about the shape of the object, or encountering TypeErrors:

  1. const zipCode = getZipCode(user);
  2. console.log(zipCode); // undefined

Docs" class="reference-link">Docs

Documentation generated via JSDoc.


Migrating from 1.x to 2.x" class="reference-link">Migrating from 1.x to 2.x

Breaking changes were introduced in 2.0.0; the following redundant function were removed.

Maybe.of() can replicate the behavior of prop, props, and path.

prop(val: string | number)

  1. const obj = Maybe.of({
  2. foo: {
  3. bar: [123, 456]
  4. }
  5. });
  6. // Incorrect
  7. const bar = obj.prop("foo").join(); // { bar: [123, 456] }
  8. // Correct
  9. Maybe.of(() => obj.join().foo).join(); // { bar: [123, 456] }
  10. // Incorrect
  11. obj
  12. .prop("foo")
  13. .prop("bar")
  14. .prop(1)
  15. .join(); // 456
  16. // Correct
  17. Maybe.of(() => obj.join().foo.bar[1]).join() // 456

props(...args)

  1. const obj = Maybe.of({
  2. foo: 'bar',
  3. baz: [1,2,3]
  4. });
  5. // Incorrect
  6. obj.props('baz', 0).join(); // 1
  7. // Correct
  8. Maybe.of(() => obj.join().baz[0]).join(); // 1

props(val: string)

  1. const obj = Maybe.of({
  2. foo: 'bar',
  3. baz: [1,2,3]
  4. });
  5. // Incorrect
  6. obj.path('baz.0').join() // 1
  7. // Correct
  8. Maybe.of(() => obj.join().baz[0]).join(); // 1

API" class="reference-link">API

Check out the API below, or the complete documentation.

of(val: unknown | OfTypeFunc<T>)" class="reference-link">of(val: unknown | OfTypeFunc<T>)

Accepts a value of any type, and returns a monad:

  1. const str = Maybe.of('foo');
  2. const num = Maybe.of(123);
  3. const bool = Maybe.of(true);
  4. const obj = Maybe.of({});
  5. const arr = Maybe.of([]);
  6. const empty = Maybe.of(null);
  7. const undef = Maybe.of(undefined);

Accepts a function, and sets the function’s return value as the monad’s value, returns a monad.

If the function results in an error, the monad’s value is set to undefined.

  1. type OfTypeFunc<T> = () => T;
  2. const user = {};
  3. const mZipCode = Maybe.of(() => user.address.zipCode);
  4. console.log(mZipCode.join()); // undefined

isJust(): boolean" class="reference-link">isJust(): boolean

Returns true if the value is not null or undefined:

  1. Maybe.of(123).isJust(); // true
  2. Maybe.of(null).isJust(); // false

isNothing(): boolean" class="reference-link">isNothing(): boolean

Returns true if the value is null or undefined:

  1. Maybe.of(123).isNothing(); // false
  2. Maybe.of(null).isNothing(); // true

join(): T" class="reference-link">join(): T

Returns the value:

  1. Maybe.of(123).join(); // 123
  2. Maybe.of(null).join(); // null

orElse(defaultValue: unknown): Maybe" class="reference-link">orElse(defaultValue: unknown): Maybe

Chain to the end of a monad to return as the default value if isNothing() is true:

  1. Maybe.of(undefined)
  2. .orElse('No Value')
  3. .join(); // 'No Value'

map(transform: (val: T) => T | Maybe<T>): Maybe" class="reference-link">map(transform: (val: T) => T | Maybe<T>): Maybe

Apply a transformation to the monad, and return a new monad:

  1. const val = 1;
  2. const newVal = Maybe.of(val).map(val => val + 1);
  3. newVal.join(); // 2;

chain(chain: (val: T) => Maybe<T>): Maybe" class="reference-link">chain(chain: (val: T) => Maybe<T>): Maybe

Chain together functions that return Maybe monads:

  1. function addOne (val) {
  2. return Maybe.of(val + 1);
  3. }
  4. const three = Maybe.of(1)
  5. .chain(addOne)
  6. .chain(addOne);
  7. three.join(); // 3

Credit" class="reference-link">Credit

Credit to James Sinclair for writing The Marvellously Mysterious JavaScript Maybe Monad.