declarative-optional
TypeScript icon, indicating that this package has built-in type declarations

2.1.10 • Public • Published

Build Coverage License Version

Declarative-Optional

A Javascript library to write concise functional code.Combined with features of Java Optional & Javascripts Promise chaining

Features

Lazily evaluated

chaining async and sync functions

Most of the Java Optional Features

Some of the Java Stream Features


Installation
    npm install declarative-optional   
Usage

To Import

// Common JS
    const {Optional} = require( "declarative-optional");

//ES6
    import {Optional} from "declarative-optional";

Common Usages


//Increment By 5 
  function incrementByFive(input) {
        return Optional.of(input)
            .map(i=>i+5)
            .orElse(0)
    }


// incrementByFive(41)  => 46
// incrementByFive(null)  => 0
// incrementByFive(undefined)  => 0



// All the expressions will be evaluated only after you specified get()

//Increment a Number by 5, Only if its dividable by 5
Optional.of(input)
    .filter(val=>val % 5 == 0)
    .map(val=>val+5)
    .get()


   

On Asynchronous code

// Consider the async function

function getFromUserService({username, password}) {
    return new Promise((function (resolve) {
        resolve({name: "user", isAdmin: true})
    }))
}

async function login({username, password}) {

    if (null == username || null == password) {
        throw new Error("Cannot be Null")
    }

    const result = await getFromUserService(username, password)


    if (result.isAdmin) {
        redirectTo("adminPage")
    } else {
        redirectTo("userPage")
    }

}

// With Declarative Optional
async function login({username, password}) {


    const page = await Optional.of({username: user, password: pass})
        .filter(({username, password}) => (null != username && null != password))
        .map(getFromUserService)
        .map(result => result.isAdmin ? "adminPage" : "userPage")
        .toAsync();


    page.ifPresentOrElse(redirectTo, () => {
        throw new Error("Cannot be Null")
    })
}

fetch Api with Optional

    // Typical code 

    const url  ='https://jsonplaceholder.typicode.com/todos/' + item
    const rawResults = await fetch(url);
    const response = await rawResults.json();

    if (response.completed) {
        return response.title
    } else {
        return null
    }

    
    // Can be rewritten with optional as 
    return await Optional.of('https://jsonplaceholder.typicode.com/todos/' + item)
        .map(fetch)
        .map(response => response.json())
        .filter(response => response.completed == true)
        .map(response => response.title)
        .getAsync();

   
    

There are so much you can play with declarative suite. It does have some features similar to Java Optional & RX libraries, except the code is small (one file around 4 Kb original source) and simple.

It also features a stream library, a wrapper for array , with lazy evaluation and functional programming features.

//commonjs
    const {Stream} = require("declarative-optional");

//ES6
    import {Stream} from "declarative-optional";
    
    
    const results = Stream.of([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
        .filter(val => val % 2 == 0)
        .map(val => val * 2)
        .get();

    console.log(stream) // [4,8,12,16,20]
    
    
    // first
    Stream.of([45,46,80])
        .first()
        .get()
    // [45]
    
    
    
    // last
    Stream.of([45,46,80])
        .last()
        .get()
    // [80]
    
    //The first and last methods are useful when you want to get the first or last element of a stream and also you can chain up map operations.

    Stream.of([45,46,80])
        .last()
        .map(val=>val*2)
        .get()
    // [160]
    

// Async Stream
    const input = [Promise.resolve(21),Promise.resolve(25),Promise.resolve(30)]
    const result = await Stream.of(input)
        .filter((value) => value %5 ==0)
        .map(getFromUserService)
        .getAsync()
    
    // [25,30]
    
    
// handle async errors or empty values with default value

    const input = [Promise.resolve(21),Promise.reject(25),Promise.resolve(30)]
    const val = await Stream.of(input)
        .filter((value) => value %5 ==0)
        .map(getFromUserService)
        .orElseAsync(["default"])

    // ["default"]    

Documentation

Function Description Example
Optional.of To create a new Optional .Can be value or promise or null or undefined
 Optional.of(input)

map convert from one form to other, returns optional instance, can return async functions as well
  Optional.of(21)
  .map(val => val + 1)

filter apply a predicate function over a value
  Optional.of(21)
  .filter(val => val % 5 == 0)

flatmap if an existing function returns Optional , it will flatten the value and pass it below
// Consider a function which will return Optional
//returns Optional 
const powersOf = (name)=>Optional.of(['web-shooters','syntheitic-webbing'])

const superHeroById = (id) =>  "Spider-Man"

const res  = Optional.of(52001)
    .map(superHeroById)
    .map(powersOf )
    .flatten()
    .get()

// results ['web-shooters','syntheitic-webbing']

const res  = Optional.of(52001)
    .map(superHeroById)
    .flatmap(powersOf )
    .get()

// results ['web-shooters','syntheitic-webbing']

get evaluate all the chained functions and give the result. If no value is available , will return null
  Optional.of(21)
  .filter(val => val % 5 == 0)
  .map(val => val + 5)
  .get() ;  // returns null

  Optional.of(20)
  .filter(val => val % 5 == 0)
   .map(val => val + 5)
  .get() ;  // returns 25

Error

  Optional.of(input)      
   .map(promiseFunctionToValidateUserDetails)
   .map(promiseFunctionToValidateSomeOther)
  .get() ;  

// Error ? Use getAsync to deal with promises

orElse Evaluate all the chained functions and if result exists, give the result. If no value is available , will return value passed by
  Optional.of(21)
  .filter(val => val % 5 == 0)
  .map(val => val + 5)
  .orElse(45) ;  // returns 45 , as the evaluation will return null

  Optional.of(20)
  .filter(val => val % 5 == 0)
   .map(val => val + 5)
  .orElse(45) ;  // returns 25

stream Evaluates all the chained functions and give an array object , if the result is already an array, it will provide as it is , if its single element, it converts to an array of single element
const res  = Optional.of([23,45])
    .stream()
    .map(i=>i+1);

//returns [24,46]

const res  = Optional.of(null)
    .stream()
    .map(i=>i+1);

//returns []

const res  = Optional.of(23)
    .stream()
    .map(i=>i+1);

//returns [24]

getAsync
Evaluate all the chained functions combined with promises give another Promise<result>

 const result = await Optional.of(input)      
               .map(promiseFunctionToValidateUserDetails)
               .map(promiseFunctionToValidateRole)
                .map(regularFunctionToFormatData)
                .getAsync()

const result = await Optional.of('https://jsonplaceholder.typicode.com/todos/' + item)
                    .map(fetch)
                    .map(response => response.json())
                    .filter(response => response.completed == true)
                    .map(response => response.title)
                    .getAsync();

The below will also work fine

  const result = await Optional.of(21)
                          .filter(val => val % 5 == 0)
                          .map(val => val + 5)
                          .getAsync()  

toAsync
Evaluate all the chained functions combined with promises give another Promise<Optional> which hold the response.

All the async based results must use toAsync and then they can use the Optional consolidation functions , get ,orElse,stream etc..

  Optional.of(input)      
   .map(promiseFunctionToValidateUserDetails)
   .map(promiseFunctionToValidateSomeOther)
  .toAsync()
   .then(optionalData=>{
        // optionalData.get() holds the result
    })

 const optionalData = await Optional.of(input)      
                   .map(promiseFunctionToValidateUserDetails)
                   .map(promiseFunctionToValidateSomeOther)
                  .toAsync()

// optionalData.get() holds the result

Alternatives

There are some alternatives , Have a look into them as well

Optional.js

amidevtech/optional.js

Package Sidebar

Install

npm i declarative-optional

Weekly Downloads

2

Version

2.1.10

License

MIT

Unpacked Size

43.5 kB

Total Files

21

Last publish

Collaborators

  • muthuishere