A Javascript library to write concise functional code.Combined with features of Java Optional & Javascripts Promise chaining
Lazily evaluated
chaining async and sync functions
Most of the Java Optional Features
Some of the Java Stream Features
npm install declarative-optional
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")
})
}
// 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"]
Function | Description | Example |
Optional.of | To create a new Optional .Can be value or promise or null or undefined |
|
map | convert from one form to other, returns optional instance, can return async functions as well |
|
filter | apply a predicate function over a value |
|
flatmap | if an existing function returns Optional , it will flatten the value and pass it below |
|
get | evaluate all the chained functions and give the result. If no value is available , will return null |
Error
|
orElse | Evaluate all the chained functions and if result exists, give the result. If no value is available , will return value passed by |
|
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 |
|
getAsync |
Evaluate all the chained functions combined with promises give another Promise<result> |
The below will also work fine
|
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.. |
|
There are some alternatives , Have a look into them as well