@bemedev/pipe
v1.6.1
Published
A utility for creating and managing pipelines in Typescript.
Maintainers
Readme
@bemedev/pipe
N.B : Open all links in a new tab to avoid losing your place in the documentation.
An elegant library for composing functions in TypeScript. Simplify your code by creating typed, performant, and fully inferred processing pipelines — with native async support.
Table of Contents
- Installation
- Quick Start
- Main API
- Utility Types
- Runtime Utilities
- Common Extensions
- String Extensions
- Boolean Extensions
- Arithmetic Extensions
- Numeric Extensions — Checkers
- CHANGELOG
Installation
pnpm
pnpm install @bemedev/pipenpm
npm install @bemedev/pipebun
bun addBy @bemedev/pipeQuick Start
import { pipe } from '@bemedev/pipe';
const add1 = (x: number) => x + 1;
const double = (x: number) => x * 2;
const piped = pipe(add1, double);
piped(2); // 6 ← (2 + 1) * 2
const processData = pipe(
(x: number) => x + 1,
x => x * 2,
x => x - 3,
x => x / 2,
x => x ** 2,
);
processData(2); // 2.25 ← ((((2+1)*2)-3)/2)²Main API
pipe
import { pipe } from '@bemedev/pipe';Creates a pipeline of functions where each function receives the result of the previous one. Typing is fully inferred, up to 100 functions.
- Only the first function can receive multiple arguments.
- Following functions receive exactly one argument.
- If at least one function is
async, the entire pipeline becomes asynchronous and returns aPromise.
Synchronous Pipeline
import { pipe } from '@bemedev/pipe';
const formatTitle = pipe(
(s: string) => s.trim(),
s => s.toLowerCase(),
s => s.replace(/\b\w/g, c => c.toUpperCase()),
s => `📌 ${s}`,
);
formatTitle(' hello world '); // '📌 Hello World'Multi-Argument Pipeline (first step only)
import { pipe } from '@bemedev/pipe';
const hypotenuse = pipe(
(a: number, b: number) => a ** 2 + b ** 2,
Math.sqrt,
);
hypotenuse(3, 4); // 5Asynchronous Pipeline
As soon as an async function is present, the final result is a Promise.
Following synchronous functions automatically receive the resolved value
(Awaited).
import { pipe } from '@bemedev/pipe';
const fetchUser = pipe(
async (id: number) => ({ id, name: 'Alice' }),
user => ({ ...user, greeting: `Hello, ${user.name}!` }),
);
const result = await fetchUser(1);
// { id: 1, name: 'Alice', greeting: 'Hello, Alice!' }Object Pipeline
import { pipe } from '@bemedev/pipe';
const enrichUser = pipe(
(user: { name: string; age: number }) => user,
u => ({ ...u, isAdult: u.age >= 18 }),
u => ({ ...u, label: `${u.name} (${u.age})` }),
);
enrichUser({ name: 'Bob', age: 25 });
// { name: 'Bob', age: 25, isAdult: true, label: 'Bob (25)' }pipe.notTyped
import { pipe } from '@bemedev/pipe';Untyped version of pipe. Allows chaining an unlimited number of
functions without generic typing constraints. Useful when the number of
functions exceeds 100 or in dynamic cases.
import { pipe } from '@bemedev/pipe';
// Chain of 100 increments
const increment100 = pipe.notTyped(
...Array.from({ length: 100 }, () => (x: number) => x + 1),
);
increment100(0); // 100import { pipe } from '@bemedev/pipe';
// Dynamic pipeline construction
const steps: Array<(x: string) => string> = [
s => s.trim(),
s => s.toUpperCase(),
s => `[${s}]`,
];
const format = pipe.notTyped(...steps);
format(' hello '); // '[HELLO]'Utility Types
Exported from @bemedev/pipe.
Fn<Args, R>
Base type for any function.
import type { Fn } from '@bemedev/pipe';
type Double = Fn<[number], number>;
// equivalent to: (x: number) => number
const double: Double = x => x * 2;
const result = pipe(double)(5); // 10NextFn<T>
Type of a function that takes as argument the resolved return type
(Awaited<ReturnType<T>>) of another function.
import type { Fn, NextFn } from '@bemedev/pipe';
type Step1 = Fn<[number], Promise<string>>;
type Step2 = NextFn<Step1>; // (arg: string) => anyTupleOfLength<T, N>
Constructs a tuple of exact length N where each element is of type T.
import type { TupleOfLength } from '@bemedev/pipe';
type Three = TupleOfLength<number, 3>; // [number, number, number]MaybePromise<T>
Returns Promise<Last> if at least one element of tuple T is a
Promise, otherwise returns Last directly.
import type { MaybePromise } from '@bemedev/pipe';
type Sync = MaybePromise<[number, string]>; // string
type Async = MaybePromise<[Promise<number>, string]>; // Promise<string>MaybePromiseFn<Args, R>
Type of a resulting pipeline function: synchronous or asynchronous based on
the content of R.
import type { MaybePromiseFn } from '@bemedev/pipe';
type SyncPipe = MaybePromiseFn<[number], [number, string]>;
// (...args: [number]) => string
type AsyncPipe = MaybePromiseFn<[number], [Promise<number>, string]>;
// (...args: [number]) => Promise<string>Runtime Utilities
Exported from @bemedev/pipe.
isFnPromise
isFnPromise(value?: unknown): value is Fn<any[], Promise<any>>Predicate returning true if value is an async function (whose
constructor.name is "AsyncFunction"). Used internally by pipe to
decide between sync or async execution.
import { pipe, isFnPromise } from '@bemedev/pipe';
const checkAsync = pipe((fn: (...args: any[]) => any) => fn, isFnPromise);
checkAsync(async () => 42); // true
checkAsync(() => 42); // falseASYNC_CONSTRUCTOR_NAME
const ASYNC_CONSTRUCTOR_NAME = 'AsyncFunction';Constant used by isFnPromise to identify async functions. Exported to
allow consistent custom checks.
import { pipe, ASYNC_CONSTRUCTOR_NAME } from '@bemedev/pipe';
const getConstructorName = pipe(
(fn: Function) => fn,
fn => fn.constructor.name,
);
getConstructorName(async () => {}); // 'AsyncFunction' === ASYNC_CONSTRUCTOR_NAME
getConstructorName(() => {}); // 'Function'Common Extensions
import { ... } from '@bemedev/pipe/extensions/common';
// or via the barrel:
import { ... } from '@bemedev/pipe/extensions';identity
identity<T>(value: T): TReturns the received value unchanged. Useful as a neutral step, type marker, or default value in a pipeline.
import { pipe } from '@bemedev/pipe';
import { identity } from '@bemedev/pipe/extensions/common';
const safeNumber = pipe((x: number | null) => x ?? 0, identity);
safeNumber(42); // 42
safeNumber(null); // 0isValue
isValue<T>(toCompare: T): (...values: T[]) => booleanReturns a variadic predicate that checks if at least one of the passed
values is strictly equal to toCompare. In a pipeline, receives a single
value from the previous step.
import { pipe } from '@bemedev/pipe';
import { isValue } from '@bemedev/pipe/extensions/common';
const isAdmin = pipe(
(user: { role: string }) => user.role,
isValue('admin'),
);
isAdmin({ role: 'admin' }); // true
isAdmin({ role: 'user' }); // falseimport { pipe } from '@bemedev/pipe';
import { isValue } from '@bemedev/pipe/extensions/common';
// Used with numeric values
const isZeroCustom = pipe((x: number) => x, isValue(0));
isZeroCustom(0); // true
isZeroCustom(42); // falseisNotValue
isNotValue<T>(toCompare: T): (...values: T[]) => booleanReturns a variadic predicate that checks if all passed values are
strictly different from toCompare. Opposite of isValue.
import { pipe } from '@bemedev/pipe';
import { isNotValue } from '@bemedev/pipe/extensions/common';
const isNotGuest = pipe(
(user: { role: string }) => user.role,
isNotValue('guest'),
);
isNotGuest({ role: 'admin' }); // true
isNotGuest({ role: 'guest' }); // falseimport { pipe } from '@bemedev/pipe';
import { isNotValue } from '@bemedev/pipe/extensions/common';
const isNonZero = pipe((n: number) => n, isNotValue(0));
isNonZero(5); // true
isNonZero(0); // falsevoidAction / tap
voidAction<S>(fn: (value: S) => void): (value: S) => S
tap<S>(fn: (value: S) => void): (value: S) => SExecutes fn as a side effect (logging, external mutation, debugging…)
and propagates the original value unchanged. tap is a strict alias of
voidAction.
import { pipe } from '@bemedev/pipe';
import { tap } from '@bemedev/pipe/extensions/common';
const processOrder = pipe(
(order: { id: number; total: number }) => order,
tap(o => console.log(`[order] received #${o.id}`)),
o => ({ ...o, total: o.total * 1.2 }),
tap(o => console.log(`[order] total with VAT: ${o.total}`)),
);
processOrder({ id: 42, total: 100 });
// logs: [order] received #42
// logs: [order] total with VAT: 120
// returns: { id: 42, total: 120 }import { pipe } from '@bemedev/pipe';
import { voidAction } from '@bemedev/pipe/extensions/common';
// Database persistence (side effect)
const saveAndReturn = pipe(
(user: { name: string }) => user,
voidAction(user => db.save(user)), // always returns user
user => ({ ...user, saved: true }),
);flatten
flatten<T>(ob: T): Record<string, unknown>Aplatit récursivement un objet imbriqué en un objet à un seul niveau, avec
des clés en notation pointée ("a.b.c"). Les tableaux ne sont pas
aplatis.
import { pipe } from '@bemedev/pipe';
import { flatten } from '@bemedev/pipe/extensions/common';
const normalise = pipe(
(obj: { address: { city: string; zip: string }; name: string }) => obj,
flatten,
);
normalise({ address: { city: 'Paris', zip: '75001' }, name: 'Alice' });
// { 'address.city': 'Paris', 'address.zip': '75001', name: 'Alice' }import { pipe } from '@bemedev/pipe';
import { flatten } from '@bemedev/pipe/extensions/common';
// Useful for comparing or serializing deep structures
const deepEqual = pipe(
(pair: [object, object]) => pair,
([a, b]) => [flatten(a), flatten(b)] as const,
([fa, fb]) => JSON.stringify(fa) === JSON.stringify(fb),
);
deepEqual([{ a: { b: 1 } }, { a: { b: 1 } }]); // true
deepEqual([{ a: { b: 1 } }, { a: { b: 2 } }]); // falsemapArray
// Signature with 1 key → returns value directly
mapArray<K>(key: K): (obj: Record<K, T>) => T
// Signature with N keys → returns tuple
mapArray<K1, K2, ...Ks>(k1, k2, ...ks): (obj) => [T1, T2, ...]Extracts one or more properties from an object. With a single key, returns the value directly. With multiple keys, returns a tuple in the same order.
import { pipe } from '@bemedev/pipe';
import { mapArray } from '@bemedev/pipe/extensions/common';
// Extract a single property
const getName = pipe(
(user: { name: string; age: number; role: string }) => user,
mapArray('name'),
);
getName({ name: 'Alice', age: 30, role: 'admin' }); // 'Alice'import { pipe } from '@bemedev/pipe';
import { mapArray } from '@bemedev/pipe/extensions/common';
// Extract multiple properties → typed tuple
const getCredentials = pipe(
(user: { name: string; age: number; token: string }) => user,
mapArray('name', 'token'),
);
getCredentials({ name: 'Bob', age: 25, token: 'abc123' });
// ['Bob', 'abc123']import { pipe } from '@bemedev/pipe';
import { mapArray } from '@bemedev/pipe/extensions/common';
// Chaining after flatten
const getCityAndZip = pipe(
(user: { address: { city: string; zip: string } }) => user.address,
mapArray('city', 'zip'),
);
getCityAndZip({ address: { city: 'Lyon', zip: '69001' } });
// ['Lyon', '69001']monad
monad<T>(
helper: (branch: BranchF<T>) => Branch<T>[]
): (value: T) => ReturnTypeApplies the first branch whose condition is met and returns its transformation. If no branch matches, the value is returned unchanged. Enables expressive pattern-matching inside a pipeline with improved type safety and semantic clarity.
Each branch is an object { cond, fn } :
cond: (value: T) => value is R— type guard conditionfn: (value: R) => any— transformation for the matched type
import { pipe } from '@bemedev/pipe';
import { monad } from '@bemedev/pipe/extensions/common';
// Clamp a value between 0 and 100
const clamp = pipe(
(x: number) => x,
monad(branch => [
branch(
(x): x is number => x < 0,
() => 0,
),
branch(
(x): x is number => x > 100,
() => 100,
),
]),
);
clamp(-5); // 0
clamp(50); // 50
clamp(120); // 100import { pipe } from '@bemedev/pipe';
import { monad } from '@bemedev/pipe/extensions/common';
// Normalize HTTP status to label
const statusLabel = pipe(
(code: number) => code,
monad(branch => [
branch(
(c): c is number => c >= 500,
() => 'Erreur serveur',
),
branch(
(c): c is number => c >= 400,
() => 'Erreur client',
),
branch(
(c): c is number => c >= 300,
() => 'Redirection',
),
branch(
(c): c is number => c >= 200,
() => 'Succès',
),
]),
);
statusLabel(200); // 'Succès'
statusLabel(404); // 'Erreur client'
statusLabel(503); // 'Erreur serveur'
statusLabel(100); // 100 ← no branch matched → value unchangedimport { pipe } from '@bemedev/pipe';
import { monad } from '@bemedev/pipe/extensions/common';
// Type discrimination in a union pipeline
const describe = pipe(
(x: number | string | boolean) => x,
monad(branch => [
branch(
(x): x is number => typeof x === 'number',
x => `nombre: ${x}`,
),
branch(
(x): x is string => typeof x === 'string',
x => `chaîne: "${x}"`,
),
branch(
(x): x is boolean => typeof x === 'boolean',
x => `booléen: ${x}`,
),
]),
);
describe(42); // 'nombre: 42'
describe('hello'); // 'chaîne: "hello"'
describe(true); // 'booléen: true'toggleMonad
// Positional form
toggleMonad<T>(
condition: (value: T) => boolean,
truthy: (value: T) => T,
falsy?: (value: T) => T,
): (value: T) => T
// Object form
toggleMonad<T>({
condition?: (value: T) => boolean,
truthy: (value: T) => T,
falsy?: (value: T) => T,
}): (value: T) => TApplies truthy if condition is met, falsy otherwise. If falsy is
omitted, the input value is returned as-is. In object form, condition is
also optional: if absent, truthy is always applied.
import { pipe } from '@bemedev/pipe';
import { toggleMonad } from '@bemedev/pipe/extensions/common';
// Absolute value (positional form)
const abs = pipe(
(x: number) => x,
toggleMonad(
x => x < 0,
x => -x,
x => x,
),
);
abs(-7); // 7
abs(3); // 3import { pipe } from '@bemedev/pipe';
import { toggleMonad } from '@bemedev/pipe/extensions/common';
// Normalize a score (object form)
const normaliseScore = pipe(
(score: number) => score,
toggleMonad({
condition: s => s > 20,
truthy: () => 20,
falsy: s => s,
}),
);
normaliseScore(25); // 20
normaliseScore(17); // 17String Extensions
import { ... } from '@bemedev/pipe/extensions/strings';
// or via the barrel:
import { ... } from '@bemedev/pipe/extensions';toUpperCase
toUpperCase(value: string): stringConverts a string to uppercase (locale).
import { pipe } from '@bemedev/pipe';
import { trim, toUpperCase } from '@bemedev/pipe/extensions/strings';
const shout = pipe(trim, toUpperCase);
shout(' bonjour '); // 'BONJOUR'toLowerCase
toLowerCase(value: string): stringConverts a string to lowercase (locale).
import { pipe } from '@bemedev/pipe';
import { trim, toLowerCase } from '@bemedev/pipe/extensions/strings';
const normalise = pipe(trim, toLowerCase);
normalise(' HELLO '); // 'hello'trim
trim(value: string): stringRemoves leading and trailing whitespace from a string.
import { pipe } from '@bemedev/pipe';
import { trim, capitalize } from '@bemedev/pipe/extensions/strings';
const clean = pipe(trim, capitalize);
clean(' alice in wonderland '); // 'Alice in wonderland'capitalize
capitalize(value: string): stringCapitalizes the first character only (locale), leaves the rest intact.
import { pipe } from '@bemedev/pipe';
import {
trim,
toLowerCase,
capitalize,
} from '@bemedev/pipe/extensions/strings';
const formatSentence = pipe(trim, toLowerCase, capitalize);
formatSentence(' ALICE IN WONDERLAND '); // 'Alice in wonderland'escapeRegExp
escapeRegExp(value: string): stringÉchappe tous les caractères spéciaux de la regex (.*+?^${}()|[]\) pour
permettre une utilisation sûre de la chaîne dans une expression régulière.
import { pipe } from '@bemedev/pipe';
import { escapeRegExp } from '@bemedev/pipe/extensions/strings';
const toSafePattern = pipe(
(s: string) => s,
escapeRegExp,
escaped => new RegExp(escaped, 'g'),
);
toSafePattern('1+1=2'); // /1\+1=2/g — + character properly escapedreplaceAll
replaceAll(...toRemove: string[]): (value: string) => stringRemoves all occurrences of each listed string from the input value. Each
occurrence is searched with a global RegExp derived from escapeRegExp.
import { pipe } from '@bemedev/pipe';
import { trim, replaceAll } from '@bemedev/pipe/extensions/strings';
const sanitize = pipe(
trim,
replaceAll('<script>', '</script>', 'javascript:'),
);
sanitize(' <script>alert(1)</script> ');
// 'alert(1)'import { pipe } from '@bemedev/pipe';
import {
trim,
toLowerCase,
replaceAll,
} from '@bemedev/pipe/extensions/strings';
// Slug cleanup
const toSlug = pipe(
trim,
toLowerCase,
replaceAll(' ', '.', ',', '!', '?'),
);
toSlug(' Hello, World! '); // 'hello'concat
concat(...strings: string[]): (value: string) => stringConcatenates the provided strings after the input value.
import { pipe } from '@bemedev/pipe';
import {
trim,
capitalize,
concat,
} from '@bemedev/pipe/extensions/strings';
const greet = pipe(trim, capitalize, concat(', bienvenue !'));
greet(' alice '); // 'Alice, bienvenue !'import { pipe } from '@bemedev/pipe';
import { toUpperCase, concat } from '@bemedev/pipe/extensions/strings';
// Add file extension
const toFilename = pipe(toUpperCase, concat('.md'));
toFilename('readme'); // 'README.md'Boolean Extensions
import { ... } from '@bemedev/pipe/extensions/booleans';
// or via the barrel:
import { ... } from '@bemedev/pipe/extensions';toggle
toggle(value: boolean): booleanInverts a boolean (true → false, false → true).
import { pipe } from '@bemedev/pipe';
import { toggle } from '@bemedev/pipe/extensions/booleans';
const invert = pipe((flag: boolean) => flag, toggle);
invert(true); // false
invert(false); // trueimport { pipe } from '@bemedev/pipe';
import { toggle } from '@bemedev/pipe/extensions/booleans';
// Double inversion = identity
const noOp = pipe(toggle, toggle);
noOp(true); // true
noOp(false); // falsetoNumber
toNumber(value: boolean): numberConverts a boolean to a number (true → 1, false → 0).
import { pipe } from '@bemedev/pipe';
import { toggle, toNumber } from '@bemedev/pipe/extensions/booleans';
const boolToScore = pipe((flag: boolean) => flag, toNumber);
boolToScore(true); // 1
boolToScore(false); // 0import { pipe } from '@bemedev/pipe';
import { toggle, toNumber } from '@bemedev/pipe/extensions/booleans';
// Invert then convert
const invertedScore = pipe(toggle, toNumber);
invertedScore(true); // 0
invertedScore(false); // 1Arithmetic Extensions
import { ... } from '@bemedev/pipe/extensions/numbers/arithmetic';
// or via the barrel:
import { ... } from '@bemedev/pipe/extensions';All operations follow the convention operation(toApply)(value) =
fn(value, toApply). So addBy(10)(5) = 5 + 10 = 15.
operation
operation(fn: (a: number, b: number) => number): (toApply: number) => (value: number) => numberFactory for curried arithmetic operations. Used to create addBy,
timesBy, divisionBy, moduloBy, and exponentBy. Allows defining any
custom binary operation.
import { pipe } from '@bemedev/pipe';
import { operation } from '@bemedev/pipe/extensions/numbers/arithmetic';
const squareRoot = operation((a, b) => a ** (1 / b));
const sqrt = pipe((x: number) => x, squareRoot(2));
sqrt(9); // 3
sqrt(16); // 4addBy
addBy(n: number): (value: number) => numberAdds n to the value.
import { pipe } from '@bemedev/pipe';
import { addBy } from '@bemedev/pipe/extensions/numbers/arithmetic';
const addTax = pipe((price: number) => price, addBy(20));
addTax(100); // 120timesBy
timesBy(n: number): (value: number) => numberMultiplies the value by n.
import { pipe } from '@bemedev/pipe';
import { timesBy } from '@bemedev/pipe/extensions/numbers/arithmetic';
const double = pipe((x: number) => x, timesBy(2));
double(7); // 14divisionBy
divisionBy(n: number): (value: number) => numberDivides the value by n.
import { pipe } from '@bemedev/pipe';
import { divisionBy } from '@bemedev/pipe/extensions/numbers/arithmetic';
const half = pipe((x: number) => x, divisionBy(2));
half(42); // 21moduloBy
moduloBy(n: number): (value: number) => numberReturns the remainder of dividing the value by n.
import { pipe } from '@bemedev/pipe';
import { moduloBy } from '@bemedev/pipe/extensions/numbers/arithmetic';
const remainder = pipe((x: number) => x, moduloBy(3));
remainder(10); // 1 ← 10 % 3
remainder(9); // 0exponentBy
exponentBy(n: number): (value: number) => numberRaises the value to the power n.
import { pipe } from '@bemedev/pipe';
import { exponentBy } from '@bemedev/pipe/extensions/numbers/arithmetic';
const square = pipe((x: number) => x, exponentBy(2));
square(5); // 25
square(3); // 9Combined Example: Complete Arithmetic Formula
import { pipe } from '@bemedev/pipe';
import {
addBy,
timesBy,
divisionBy,
moduloBy,
exponentBy,
} from '@bemedev/pipe/extensions/numbers/arithmetic';
const formula = pipe(
(x: number) => x,
addBy(10), // + 10
timesBy(3), // × 3
divisionBy(5), // ÷ 5
moduloBy(7), // % 7
exponentBy(2), // ²
);
formula(5); // (((5+10)×3)÷5)%7)² = (9%7)² = 4Numeric Extensions — Checkers
import { ... } from '@bemedev/pipe/extensions/numbers/checkers';
// or via the barrel:
import { ... } from '@bemedev/pipe/extensions';isZero
isZero(...values: number[]): booleanReturns true if the value is strictly equal to 0. Equivalent to
isValue(0).
import { pipe } from '@bemedev/pipe';
import { isZero } from '@bemedev/pipe/extensions/numbers/checkers';
const checkDenominator = pipe((n: number) => n, isZero);
checkDenominator(0); // true ← division impossible
checkDenominator(5); // falseisNotZero
isNotZero(...values: number[]): booleanReturns true if the value is strictly different from 0. Equivalent to
isNotValue(0).
import { pipe } from '@bemedev/pipe';
import { isNotZero } from '@bemedev/pipe/extensions/numbers/checkers';
import { divisionBy } from '@bemedev/pipe/extensions/numbers/arithmetic';
const safeDivide = pipe((n: number) => n, isNotZero);
safeDivide(5); // true ← can divide
safeDivide(0); // false ← division by zerocompare
compare(toCompare: number): (value: number) => -1 | 0 | 1Compares the value to toCompare and returns:
0if equal1ifvalue > toCompare-1ifvalue < toCompare
import { pipe } from '@bemedev/pipe';
import { compare } from '@bemedev/pipe/extensions/numbers/checkers';
const compareToTen = pipe((x: number) => x, compare(10));
compareToTen(5); // -1 ← 5 < 10
compareToTen(10); // 0 ← equal
compareToTen(15); // 1 ← 15 > 10import { pipe } from '@bemedev/pipe';
import { compare } from '@bemedev/pipe/extensions/numbers/checkers';
// Sort an array with compare
const sortAsc = (arr: number[]) =>
[...arr].sort((a, b) => pipe((x: number) => x, compare(b))(a));
sortAsc([3, 1, 4, 1, 5]); // [1, 1, 3, 4, 5]sign
sign(value: number): -1 | 0 | 1Returns the sign of the value: 1 (positive), -1 (negative), 0 (zero).
Equivalent to compare(0).
import { pipe } from '@bemedev/pipe';
import { sign } from '@bemedev/pipe/extensions/numbers/checkers';
const classify = pipe((x: number) => x, sign);
classify(-42); // -1
classify(0); // 0
classify(7); // 1import { pipe } from '@bemedev/pipe';
import { sign } from '@bemedev/pipe/extensions/numbers/checkers';
import { map } from '@bemedev/pipe/extensions/common';
// Convert sign to label
const signLabel = pipe(
(x: number) => x,
sign,
map(branch => [
branch({ cond: s => s === -1, fn: () => 'négatif' }),
branch({ cond: s => s === 0, fn: () => 'zéro' }),
branch({ cond: s => s === 1, fn: () => 'positif' }),
]),
);
signLabel(-5); // 'negative'
signLabel(0); // 'zero'
signLabel(8); // 'positive'CHANGELOG
License
MIT
Author
chlbri ([email protected])
