Home

Awesome

context-fp

logo

Microscopic functional programming context for TypeScript <br/>

Motivation

if you tired from gygantic TypeScript DI containers, based on classes and decorators, you are in the right place <br/> Just use functional programming and don't worry about context passing through functions, it's with you

Features

How to

Basic example

import { cfp } from 'context-fp'
import assert from 'node:assert'

type Context = { numbers: number[] }

const positiveNumbers = ({ numbers }: Context) => numbers.filter(n => n > 0)

const numbersPrefix = () => 'Here is numbers:'

const positiveNumbersAsString = cfp(
  numbersPrefix,
  positiveNumbers,
  (prefix, numbers) => `${prefix} ${numbers.toString()}`
)

assert.strictEqual(
  positiveNumbersAsString({ numbers: [-1, -5, 7, 0, 4] }),
  'Here is numbers: 7,4'
)

Calculations cached example

import { cfp } from 'context-fp'
import assert from 'node:assert'

let called = 0

const positiveNumbers = ({ numbers }: { numbers: number[] }) =>
  (called++, numbers.filter(n => n > 0))

const positiveNumbersLength = cfp(positiveNumbers, ns => ns.length)

const positiveNumbersAsString = cfp(
  positiveNumbers,
  positiveNumbersLength,
  (ns, l) => `${ns.toString()}; length - ${l}`
)

assert.strictEqual(
  positiveNumbersAsString({ numbers: [-1, -5, 7, 0, 4] }),
  '7,4; length - 2'
)
assert.strictEqual(called, 1)

Unit tests example

import { cfp } from 'context-fp'
import assert from 'node:assert'

type Context = { numbers: number[] }

const positiveNumbers = ({ numbers }: Context) => numbers.filter(n => n > 0)

const numbersPrefix = () => 'Here is numbers:'

const positiveNumbersAsString = cfp(
  numbersPrefix,
  positiveNumbers,
  (prefix, numbers) => `${prefix} ${numbers.toString()}`
)

assert.strictEqual(
  positiveNumbersAsString.raw('Here is numbers:', [7, 4]),
  'Here is numbers: 7,4'
)

Dependency injection example

import { cfp } from 'context-fp'
import assert from 'node:assert'

const fetchUserFromDB = async (): Promise<{ name: string }> => {
  // some production implementation
}

const fetchUser = ({ fetchUser }: { fetchUser?: typeof fetchUserFromDB }) =>
  fetchUser?.() ?? fetchUserFromDB()

const helloWorldUser = cfp(
  fetchUser,
  user => user.then(({ name }) => `Hello world, ${name}!`)
)

assert.strictEqual(
  await helloWorldUser({ fetchUser: async () => ({ name: 'Vasya' }) }),
  'Hello world, Vasya!'
)

State manager example

import { cfp, sfp } from 'context-fp'
import assert from 'node:assert'

const numbers = ({ incNumber }: { incNumber: number }) =>
  sfp((ns: number[], n: number) => [...ns, n + incNumber], [])

const addNumber1 = cfp(numbers, ns => ns(1))
const addNumber2 = cfp(numbers, ns => ns(2))
const addNumber3 = cfp(numbers, ns => ns(3))

const numbersToString = cfp(
  numbers,
  addNumber1,
  addNumber2,
  addNumber3,
  ns => ns().toString()
)

assert.strictEqual(numbersToString({ incNumber: 1 }), '2,3,4')

See also