Giter Site home page Giter Site logo

spacelift's Introduction

space-lift "Lift your values into space for infinite possibilities"

Rich Array/Object wrapper, Option, Result monads

Design goals

  • 100% immutable, no magic, no overwhelming polymorphism or dynamic operators
  • Fun to use
  • Correctness and proper typescript typings
  • Tiny and performant
  • Small set of functions, configurable with lambdas
  • Cover 95% of frontend data transformation needs without becoming a bloated lib just to cover the remaining 5%
  • Use an OO style as it's the most convenient one without an |> operator directly in the language (fingers crossed)

How to use

Here's everything that can be imported from space-lift:

import lift, { Option, Some, None, Result, Ok, Err, update, deepUpdate, DELETE, range, Set, memoize, is, fromArrayLike, tuple } from 'space-lift'

lift is a generic function that can wrap an Array or Object and give it extra functionalities update, deepUpdate, DELETE come from immupdate Option, Some, None are used to work with optional values Result, Ok, Err are used to work with computation that may fail range is a factory function for Arrays of numbers Set is a factory function for objects acting as Sets is is a helper used to determine if an instance is of a particular type (e.g is.array([]) === true) fromArrayLike converts an Array like object (FileList, HTMLCollection, etc) into a standard Array tuple creates a properly typed tuple

By default, the library provides no operators to the Wrapped Arrays/Objects at all. You get to choose what to import.

The fastest way is to install everything in a single import (probably in your main file):

import 'space-lift/es/all' // For bundlers who work more efficiently with ECMAScript modules

import 'space-lift/commonjs/all' // To use the legacy commonjs modules

But you can also choose exactly what to import:

import 'space-lift/es/array/map'
import 'space-lift/es/object/mapValues'

Note: When using typescript, don't forget to enable (at least) these two flags for better type-safety: noImplicitAny, strictNullChecks

Examples

Update an object inside an Array

import lift, { update } from 'space-lift'
// or import _ from 'space-lift'  ʘ‿ʘ

const people = [
  { id: 1, name: 'jon' },
  { id: 2, name: 'sarah' },
  { id: 3, name: 'nina' }
]

const updatedPeople = lift(people)
  .findIndex(p => p.id === 2)
  .map(index => lift(people).updateAt(index, person => update(person, { name: 'Nick' })))
  .getOrElse(people)

Sort on two fields

import lift from 'space-lift'

const people = [
  { first: 'jon',   last: 'haggis' },
  { first: 'sarah', last: 'john' },
  { first: 'nina',  last: 'pedro' }
]

// This will result in an Array sorted by first name, then by last name
const sortedPeople = lift(people)
  .sort({ by: p => p.last })
  .sort({ by: p => p.first })
  .value()

Auto unwrap

Most of the time, you will have to call .value() to read your value back (or .get() for options, although it is recommended to use map/getOrElse/etc instead) Because it's distracting to write .value() more than once per chain, some operators will automatically unwrap values returned from their iterators (like Promise->then). These operators are:

  • Option.map
  • Array.map
  • Array.flatMap
  • Array.updateAt
  • transform

API

Array

TODO: Detail and examples

Object

TODO: Detail and examples

Function

memoize

import { memoize } from 'space-lift'

function multiply(a: number, b: number) {
  return a * b
}

// Using reference equality on every arg
const memoizedMultiply = memoize(multiply)


const myObj = { id: 10 }

// Using memo keys
const memoized = memoize(
  (a: number, b: typeof myObj): {} => ({ x: a, y: b }),
  { key: (a, b) => `${a}_${b.id}` }
)

Option

Creating an Option

Option(x)

Creates an Option from a value. If the value is null or undefined, it will create a None, else a Some.

const some = Option(33) // some === Some(33)
const none = Option(null) // none === None

If you already know the value is defined for sure (not nullable) or not, you can create a Some or None directly:

const some = Some(33) // Some(null | undefined) wouldn't compile.
const none = None

Option.all([...optionsOrValues])

Creates a new Option holding the tuple of all the values contained in the passed array if they were all Some or non null/undefined values, else returns None

const some = Option.all([
  Option(10),
  20,
  Option(5)
])
// some === Some([10, 20, 5])

const none = Option.all([
  Option(10),
  None,
  Option(5),
  null
])
// none === None

Option.isOption

Returns whether the passed instance in an Option, and refines its type

import { Option, Some } from 'space-lift'
Option.isOption(Some(33)) // true

None

The Option constant representing no value.

import { None } from 'space-lift'

Transforming an Option

map

Maps the value contained in this Some, else returns None. Depending on the map function return value, a Some could be tranformed into a None, as a Some is guaranteed to never contain a null or undefined value.

const some = Option(33).map(x => x * 2)
// some === Some(66)

flatMap

Maps the value contained in this Some to a new Option, else returns None.

const some = Option(33).flatMap(_ => Option(44))
// some === Some(44)

filter

If this Option is a Some and the predicate returns true, keep that Some. In all other cases, return None.

const some = Option(33).filter(x => x > 32)
// some === Some(33)

fold

Applies the first function if this is a None, else applies the second function. Note: Since this method creates 2 functions everytime it runs, don't use in tight loops; use isDefined() instead.

const count = Option(10).fold(
  () => 100, // None
  count => count * 10 // Some
)

toArray

Transforms this option into an Array or either 1 or 0 element.

orElse

Returns this Option unless it's a None, in which case the provided alternative is returned.

const some = Option(null).orElse(() => Option(33))
// some === Some(33)

Misc

get

Some instances return their value, whereas None always return undefined. This method never throws.

const value = Some(33).get()
// value === 33

isDefined

Returns whether this Option has a defined value (i.e, it's a Some(value)) Note: this refines the type of the Option to be a Some so it's guaranteed its value is not null/undefined.

getOrElse

Returns this Option's value if it's a Some, else return the provided alternative

const value = Option(undefined).getOrElse(33)

// value === 33

forEach

Applies the given procedure to the option's value, if it is non empty.

Option(33).forEach(x => console.log(x))

contains

Returns whether this option is a Some that contain a specific value, using ===

Option(30).contains(30) // true

exists

Returns whether this option is a Some with a value satisfying the predicate.

Option(30).exists(n => n > 10) // true

Result

A Result is the result of a computation that may fail. An Ok represents a successful computation, while an Err represent the error case.

Importing Result

Here's everything that can be imported to use Results:

import { Result, Ok, Err } from 'space-lift'

const ok = Ok(10)
const err = Err('oops')

Result.isResult

Returns whether this instance is a Result (either an Ok or a Err) and refines its type

import { Result, Ok } from 'space-lift'

Result.isResult(Ok(10)) // true

Result.all

Creates a new Ok Result holding the tuple of all the values contained in the passed array if they were all Ok, else returns the first encountered Err.

import { Result, Ok, Err } from 'space-lift'

const result = Result.all([
  Ok(20),
  Err('nooo'),
  Ok(200),
  Err('oops')
]) // Err('nooo')

isOk

Returns whether this is an instance of Ok

import { Result, Ok, Err } from 'space-lift'

Ok(10).isOk() // true

map

Maps the value contained in this Result if it's an Ok, else propagates the Error.

import { Result, Ok, Err } from 'space-lift'

Ok(10).map(x => x * 2) // Ok(20)
Err(10).map(x => x * 2) // Err(10)

mapError

Maps the Error contained in this Result if it's an Err, else propagates the Ok.

import { Result, Ok, Err } from 'space-lift'

Ok(10).mapError(x => x * 2) // Ok(10)
Err(10).mapError(x => x * 2) // Err(20)

flatMap

Maps the value contained in this Result with another Result if it's an Ok, else propagates the Error. Note: It is allowed to return a Result with a different Error type.

import { Result, Ok, Err } from 'space-lift'

Ok(10).flatMap(x => Ok(x * 2)) // Ok(20)
Ok(10).flatMap(x => Err(x * 2)) // Err(20)

fold

Applies the first function if this is an Err, else applies the second function. Note: Don't use in tight loops; use isOk() instead.

import { Result, Ok, Err } from 'space-lift'

Ok(10).fold(
  err => console.error(err),
  num => num * 2
) // 20

spacelift's People

Contributors

alexgalays avatar alx-l avatar qwefgh90 avatar denis-mludek avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.