Type utilities module for Typescript and also Javascript. It can secure your application from invalid data being pushed inside and breaking things as it can shape and model your data to prevent invalid data. Check out the documentation for further details.
- Type Utils
- Table of Contents
- Installing
- Docs
- Schema types
Schema.stringSchema.numberSchema.booleanSchema.objectSchema.arraySchema.tupleSchema.recordSchema.symbolSchema.bigintSchema.asEnumSchema.asNullSchema.asUndefinedSchema.primitiveSchema.anySchema.optional- Schema helpers
Schema.andSchema.orSchema.useSchema- Validation rules
Number.nonZeroNumber.maxNumber.minArray.maxArray.minArray.uniqueString.maxString.minString.regexString.nonEmptyString.urlString.emailRecord.nonEmptyBigInt.nonZeroBigInt.maxBigInt.minSchema.use- Standard Schema Interop
toStandardSchema(guard)fromStandardSchema(schema)normalizeSchema(schema)isStandardSchema(value)StandardSchemaV1type- Available validations
isensureInterface- Match Pattern
-
match() - Util types
FnAsyncFnActionPredicateResultAsyncResultTupleSliceParamInferTag- Experimental Features
- Lambda
- Function/Lambda Currying
- Pipelines/Pipes
- pipe(value) / createPipeline(fn?)
- .pipe(transform)
- .pipe(callWith(...args))
- .pipe(apply(fn, ...args))
- tap / tapAsync
- enpipe(value) / enpipe(fn, ...args)
- Realistic async pipeline example
- Switch Expression
- Reusable switcher
- Stored switcher
- more complex matching logic / runtime branch evaluation
With NPM:
npm install @srhenry/type-utils --saveWith Yarn:
yarn add @srhenry/type-utilsIt represents a string to typescript's type infers and runtime validation
import { string } from '@srhenry/type-utils'
const isString = string() //any string
const isAvocadoString = string('avocado') //specific string
const isPatternString = string(/goo+gle/) //pattern/RegExp matched stringIt represents a number to typescript's type infers and runtime validation
import { number } from '@srhenry/type-utils'
const isNumber = number()It represents a number to typescript's type infers and runtime validation
import { boolean } from '@srhenry/type-utils'
const isBoolean = boolean()Supports the fluent .optional(), .validator(), .use(), and .toStandardSchema() APIs.
It represents a well defined object to typescript's type infers and runtime validation, which its properties are also described using the Schema helpers
import { object, string, number } from '@srhenry/type-utils'
const isMyObject = object({
foo: string(),
bar: number(),
})It represents an array to typescript's type infers and runtime validation, which its items can also be described using the Schema helpers
import { array, string, object } from '@srhenry/type-utils'
const isArray = array() // array of anything
const isMyArray = array(string()) // array of strings
const isMyObjArray = array(object({ foo: string('bar') }))
const isMyObjArray2 = array({ foo: string('bar') })It represents a fixed-length tuple to typescript's type infers and runtime validation. Each element is validated by its own schema.
import { tuple, string, number } from '@srhenry/type-utils'
const isTuple = tuple(string(), number(), string())
// TypeGuard<[string, number, string]>
// Also accepts an array of schemas:
const isPoint = tuple([number(), number()])
// TypeGuard<[number, number]>Tuples support StandardSchemaV1 inputs as entries and the fluent .optional(), .validator(), .use(), and .toStandardSchema() APIs.
It represents a record (key-value map) to typescript's type infers and runtime validation. Key and value guards can be specified for type-safe records.
import { record, string, number } from '@srhenry/type-utils'
const isRecord = record() // Record<string, any>
const isStringMap = record(string(), string()) // Record<string, string>
const isNumKeyed = record(number(), number()) // Record<number, number>Records support string | number | symbol key types, StandardSchemaV1 inputs for key/value guards, and the fluent .nonEmpty(), .optional(), .validator(), .use(), and .toStandardSchema() APIs.
It represents a symbol to typescript's type infers and runtime validation
import { symbol } from '@srhenry/type-utils'
const isSymbol = symbol()It represents a bigint to typescript's type infers and runtime validation.
import { bigint } from '@srhenry/type-utils'
const isBigint = bigint()
const isPositiveBigint = bigint().min(0n)
const isNonZeroBigint = bigint().nonZero()Supports the fluent .nonZero(), .max(n: bigint), .min(n: bigint), .optional(), .validator(), .use(), and .toStandardSchema() APIs.
It represents a closed switch values to typescript's type infers and runtime validation. It ensures your value is one of the values given in params.
import { asEnum } from "@srhenry/type-utils"
enum Status {
ready: 1,
running: 2,
stopped: 3,
}
const validStatus = [...Object.keys(Status)] as (keyof typeof Status)[]
const isStatus = asEnum(validStatus)It represents a null literal to typescript's type infers and runtime validation.
import { asNull } from '@srhenry/type-utils'
const isNull = asNull()It represents an undefined literal to typescript's type infers and runtime validation.
import { asUndefined } from '@srhenry/type-utils'
const isUndefined = asUndefined()Supports the fluent .optional(), .validator(), .use(), and .toStandardSchema() APIs.
It represents a primitive values (such as string, number, boolean, symbol, null, undefined) to typescript's type infers and runtime validation.
import { primitive } from '@srhenry/type-utils'
const isSymbol = primitive()Supports the fluent .optional(), .validator(), .use(), and .toStandardSchema() APIs.
It represents a 'any' value to typescript's type infers and runtime validation. It does nothing to validate a narrowed type but can be useful to improve readability in more complex schemas.
import { any, object } from '@srhenry/type-utils'
const isAny = any()
const objectHasFoo = object({ foo: isAny }) //it checks if is object and if has `foo` property but doesn't care checking its typeSupports the fluent .optional(), .validator(), .use(), and .toStandardSchema() APIs.
#### `Schema.optional`
> Since [`v0.5.0`](https://github.com/SrHenry/type-utils/releases/tag/v0.5.0), this method was removed, but also embeded in all exported schemas.
> Since [`v0.6.0`](https://github.com/SrHenry/type-utils/releases/tag/v0.6.0), this method was replaced to be a property in the returned type guard instead of a property of the schema.
It represents a optional value to typescript's type infers and runtime validation. You can access this schema by acessing the `.optional` property in the desired optional schema:
```typescript
import { object, string, number } from '@srhenry/type-utils'
const objectMaybeHasFoo = object({
foo: string().optional(),
bar: number().optional()
})
// it checks if is object and if has `foo`.
// if it has `foo` then check if it is string or undefined,
// if it hasn't then pass anyway as it is optional property.
It creates an intersection between two schemas.
import { object, string, and } from '@srhenry/type-utils'
const hasFoo = object({ foo: string() })
const hasBar = object({ bar: string() })
const isSomething = and(hasFoo, hasBar)It creates an union between two schemas.
import { string, boolean, or } from '@srhenry/type-utils'
const isString = string()
const isBool = boolean()
const isSomething = or(isString, isBool)It wraps a schema (just to improve readability).
import { object, string, array, useSchema } from '@srhenry/type-utils'
const hasFoo = object({ foo: string() })
const isFooArray = array(useSchema(hasFoo))It constraints a number to be different from 0.
import { number } from '@srhenry/type-utils'
const isNonZeroNumber = number().nonZero()It constraints a number to be lesser than a given number.
import { number } from '@srhenry/type-utils'
const isNonZeroNumber = number().max(255)It constraints a number to be greater than a given number.
import { number } from '@srhenry/type-utils'
const isNonZeroNumber = number().min(1)It constraints an array's size to be lesser than a given number.
import { array, any } from '@srhenry/type-utils'
const isArray = array(any()).max(25)It constraints an array's size to be greater than a given number.
import { array, any } from '@srhenry/type-utils'
const isArray = array(any()).min(2)It constraints an array to contain only distinct values, failling if a duplicate is found.
import { array, string } from '@srhenry/type-utils'
const isArray = array(string()).unique()It constraints a string's size to be lesser than a given number.
import { string } from '@srhenry/type-utils'
const isString = string().max(60)It constraints a string's size to be greater than a given number.
import { string } from '@srhenry/type-utils'
const isString = string().min(10)It constraints a string to match a given pattern (regular expression).
import { string } from '@srhenry/type-utils'
const isNumericString = string(/[0-9]+/)
// or using fluent pattern:
const isNumericString2 = string().regex(/[0-9]+/)It constraints a string's size to be greater than 0.
import { string } from '@srhenry/type-utils'
const isString = string().nonEmpty()It constraints a string to be a valid url representation.
import { string } from '@srhenry/type-utils'
const isStringUrl = string().url()It constraints a string to be a valid email representation.
import { string } from '@srhenry/type-utils'
const isStringEmail = string().email()It constrains a record to not be empty.
import { record } from '@srhenry/type-utils'
const isNonEmptyRecord = record().nonEmpty()It constraints a bigint to be different from 0n.
import { bigint } from '@srhenry/type-utils'
const isNonZeroBigint = bigint().nonZero()It constraints a bigint to be lesser than or equal to a given bigint.
import { bigint } from '@srhenry/type-utils'
const isMaxBigint = bigint().max(100n)It constraints a bigint to be greater than or equal to a given bigint.
import { bigint } from '@srhenry/type-utils'
const isMinBigint = bigint().min(1n)Since
v0.6.0
It allows you to create custom validation rules to be used in schemas.
import { string, createRule } from '@srhenry/type-utils'
const StringNumber = createRule({
name: "Custom.StringNumber",
message: "number",
handler: (value: string) => () => !Number.isNaN(Number(value)),
});
const isStringNumber = string().use(StringNumber())Since
v0.6.1
It allows you to get a validator instance to validate a value against the schema.
import { string, or, object, createInlineRule, createRule } from '@srhenry/type-utils'
const StringNumber = createRule({
name: "Custom.StringNumber",
message: "number",
handler: (value: string) => () => !Number.isNaN(Number(value)),
});
const isStringNumberOrObject = or(
string()
.use(createInlineRule("Custom.StringNumber", (value: string) => !Number.isNaN(Number(value)))),
object({
foo: string().use(StringNumber()),
bar: string().optional()
}));Since
v0.7.0
type-utils implements the Standard Schema v1 specification for interoperability with other validation libraries (Zod, Valibot, ArkType, etc.).
import { toStandardSchema, fromStandardSchema, normalizeSchema, isStandardSchema } from '@srhenry/type-utils/standard-schema'
import type { StandardSchemaV1, InferInput, InferOutput } from '@srhenry/type-utils/standard-schema'Converts a TypeGuard<T> into a StandardSchemaV1<T, T>. Also available as a fluent method on all schemas:
import { string } from '@srhenry/type-utils'
import { toStandardSchema } from '@srhenry/type-utils/standard-schema'
const guard = string()
const standard = toStandardSchema(guard)
// or using the fluent API:
const standard2 = string().toStandardSchema()
const result = standard['~standard'].validate('hello')
// { success: true, value: 'hello' }Converts a StandardSchemaV1<Input> into a synchronous TypeGuard<Input>. Throws if the external schema's validate() returns a Promise (async schemas cannot be converted to synchronous type guards).
import { fromStandardSchema } from '@srhenry/type-utils/standard-schema'
import { z } from 'zod'
const zodString = z.string()
const guard = fromStandardSchema(zodString)
// TypeGuard<string>Accepts either a TypeGuard<T> or a StandardSchemaV1<T, T> and returns a TypeGuard<T>. Useful when building APIs that accept both type-utils guards and external Standard Schema validators:
import { normalizeSchema } from '@srhenry/type-utils/standard-schema'
import { object, string } from '@srhenry/type-utils'
import { z } from 'zod'
const schema = object({
name: normalizeSchema(string()),
age: normalizeSchema(z.number()),
})Type guard that checks if a value implements the StandardSchemaV1 interface (has the '~standard' property).
The core type representing a Standard Schema v1 compliant validator. Includes the StandardSchemaV1 namespace with Props, Result, SuccessResult, FailureResult, Issue, and Options types. Utility types InferInput<T> and InferOutput<T> extract the input/output types from a StandardSchemaV1.
It checks a given value against a given schema or validator and return true if schema matches the value, otherwise return false.
import { string, is } from '@srhenry/type-utils'
//...
if (is(value, string())) {
// value is string
} else {
// value is not a string
}It checks a given value against a given schema or validator and returns the checked value with schema inferred type if schema matches the value or throws an error if schema didn't match the value. Pretty clean to use with destructuring pattern.
import { object, number, string, ensureInterface } from '@srhenry/type-utils'
//...
const { foo, bar } = ensureInterface(value, object({
foo: number(),
bar: string(),
}) //It throws an error if validation fails!
console.log('foo', foo) // foo
console.log('bar', bar) // barNOTE: You can use schema directly to validate a value.
import { object, number } from "@srhenry/type-utils"
const hasFoo = object({ foo: number() }))
//...
if (hasFoo(obj)) {
// obj is object and contains a string property named `foo`
} else {
// obj don't have a `foo` property of type string
}Create a new reusable pattern matcher object or an inline pattern matcher object for a given value.
Reusable matcher example:
import { match, object, string, array, pick } from '@srhenry/type-utils'
const matcher = match()
.with(object({ foo: string().min(3) }), obj => `Foo is valid: '${obj.foo}'`)
.with(string().nonEmpty(), str => `String is valid: '${str}'`)
.default(() => { throw new TypeError('😭') })
matcher.exec('foo') //String is valid: 'foo'
matcher.exec({ foo: 'bar' }) //Foo is valid: 'bar'
matcher.exec({ foo: 'ba' }) //TypeError: 😭
matcher.exec("") //TypeError: 😭Inline matcher example:
import { match, object, string, array, pick } from '@srhenry/type-utils'
//API endpoint processing example:
const { data } = payload
const responses = await Promise.allSettled(
match(data)
.with(object({ events: array() }), ({ events }) => events.map(e =>
match(e)
.with(
object({ type: string("USER_EVENT"), uid: string() }),
({ type: _, uid, ...data }) => UserEvent.send({ from:uid, ...data }))
.with(
object({ type: string("SYSTEM_EVENT") }),
({ type: _, ...data }) => SystemEvent.process({ ...data }))
.default(() => null)
.exec()))
.default(() => [])
.exec()
.filter(Boolean))
.then(results =>
results.map(result => match(result)
.with(
object({ status: string("fulfilled") }),
({ value }) => parseToResponse(value))
.with(
object({ status: string("rejected") }), ({ reason }) => {
log.error('Event processing failed:', reason)
switch(reason.type) {
case 'UserEventError':
//specific handling for user event errors
return UserEventError.from(reason)
break;
case 'SystemError':
//specific handling for system event errors
return SystemError.from(reason)
break;
default:
return reason
}})
.exec()))
return new JsonResponse({ success:true, event_responses: responses }) //formatted responseIt represents a synchronous function type. It has two type parameters: the first is a tuple representing the function parameters types, and the second is the return type of the function.
import type { Fn } from '@srhenry/type-utils'
declare const fn: Fn<[number, number], number> // fn: (arg_0: number, arg_1: number) => numberIt represents an asynchronous function type. It has two type parameters: the first is a tuple representing the function parameters types, and the second is the resolved return type of the function.
import type { AsyncFn } from '@srhenry/type-utils'
declare const fn: AsyncFn<[number, number], number> // fn: (arg_0: number, arg_1: number) => Promise<number>It represents a synchronous function type that does not return any value (void). It has one type parameter: a tuple representing the function parameters type.
import type { Action } from '@srhenry/type-utils'
declare const fn: Action<[string]> // fn: (arg_0: string) => voidIt represents a predicate function type. It has one type parameter: a tuple representing the function parameters type.
import type { Predicate } from '@srhenry/type-utils'
declare const fn: Predicate<[any]> // fn: (arg_0: any) => booleanIt represents an result type tuple.
It has two type parameters: the first is the success type, and the second is the failure type (optional, default Error).
import type { Result } from '@srhenry/type-utils'
declare const res1: Result<number> // res1: [null, number] | [Error, null]
declare const res2: Result<string, TypeError> // res2: [null, string] | [TypeError, null]It represents an asynchronous result type tuple.
It has two type parameters: the first is the success type, and the second is the failure type (optional, default Error).
import type { AsyncResult } from '@srhenry/type-utils'
declare const res1: AsyncResult<number> // res1: [null, number] | [Error, null]
declare const res2: AsyncResult<string, TypeError> // res2: [null, string] | [TypeError, null]It slices a tuple type. It has three type parameters: the first is the tuple type to be sliced, the second is the start index (inclusive), and the third is the end index (exclusive, optional, default to tuple length).
import type { TupleSlice } from '@srhenry/type-utils'
declare const res1: TupleSlice<[number, string, boolean], 1> // res1: [string, boolean]
declare const res2: TupleSlice<[number, string, boolean], 1, 2> // res2: [string]It extracts the type of a function parameter by its index. It has two type parameters: the first is the function type, and the second is the parameter index.
import type { Param } from '@srhenry/type-utils'
declare const res1: Param<(a: number, b: string) => void, 0> // res1: number
declare const res2: Param<(a: number, b: string) => void, 1> // res2: stringIt infers the type from a type guard function. It has one type parameter: the type guard function type.
import { type Infer, array } from '@srhenry/type-utils'
declare const isArray = array()
declare const res1: Infer<(a: unknown) => a is number> // res1: number
declare const res2: Infer<(a: unknown) => a is string[]> // res2: string[]
declare const res3: Infer<typeof isArray> // res3: any[]It creates a nominal/branded type by attaching a unique tag to a base type. Useful for distinguishing types that share the same underlying structure.
import type { Tag } from '@srhenry/type-utils'
type UserId = Tag<string, 'UserId'>
type OrderId = Tag<string, 'OrderId'>
declare function getUser(id: UserId): void
declare function getOrder(id: OrderId): void
const userId = 'abc' as UserId
getUser(userId) // ok
// getOrder(userId) // type error — UserId is not OrderIdIt has two required type parameters: the base type and the tag name (a PropertyKey). An optional third parameter Metadata defaults to void.
This was inspired in C# Lambdas, equivalent to arrow functions in Javascript/Typescript, but this helper adds invoke() method to a function instance. useful to improve readability when you have a function that returns another and you wanna call 'em all in a row, using fluent pattern.
import { Experimental } from '@srhenry/type-utils'
const { lambda } = Experimental
function builder(locales: string | string[] = 'en-US') {
function formatter(
options: Intl.DateTimeFormatOptions = {
dateStyle: 'short',
timeStyle: 'short',
}
) {
function format(date: Date | string) {
return new Intl.DateTimeFormat(locales, options).format(new Date(date))
}
return lambda(format)
}
return lambda(formatter)
}
console.log(
'1970-01-01T00:00 =',
builder('en-UK').invoke({ dateStyle: 'long' }).invoke('1970-01-01')
) // 01 January 1970This does type-wisely curries a function or lambda, in two flavors: allowing or not partial param applying (default is not allowed). The process of currying a function is traditionally a techique that allows you to call the refered function passing one parameter at a time, returning another function to further apply remaining parameters, then returning whatever the original function returns after all parameters were given to curried function. In Javascript this techinque usually allows partial apply, and in that way you can pass more than one parameter at a time, and everything else remains equal to the traditional currying.
import { Experimental } from '@srhenry/type-utils'
const { lambda, curry } = Experimental
// lets reuse earlier example:
function builder(
locales: string | string[],
options: Intl.DateTimeFormatOptions,
date: Date | string
) {
return new Intl.DateTimeFormat(locales, options).format(new Date(date))
}
const curried = curry(builder)
const curriedLambda = curry(lambda(builder))
console.log(
curried('en-GB')({ timeStyle: 'short', timeZone: 'Etc/Greenwich' })(
new Date('2020-05-10T22:35:08Z')
)
) // 22:35
console.log(
curriedLambda('en-US')
.invoke({ dateStyle: 'short', timeStyle: 'short', timeZone: 'America/New_York' })
.invoke(new Date('2020-05-10T22:35:08Z'))
) // (EDT) 5/10/20, 6:35 PMThis is a fluent API to create sync/async function pipelines. Inspired in FP pipe operator while it does not comes to Javascript/Typescript yet. It allows only single param functions, piping the return as the parameter to the next function in pipeline.
Breaking changes (experimental API):
inject()has been removed — usecallWith()for reverse-apply or a plain transform() => valuefor value replacement.pipe(enpipe(value))as reverse-apply is no longer idiomatic — use.pipe(callWith(value))instead.pipe(fn => fn(value))lambda pattern is replaced by.pipe(callWith(value)).pipe(enpipe(fn, ...args))is replaced by.pipe(apply(fn, ...args))GetPipeline<T>type has been removed — usePipe<T>insteadPipelineBoxandAsyncPipelineBoxare now standalone classes (not decorator-based)AsyncPipelineBoxno longer has.catch()— use.depipe().catch()on the promise
Creates a PipelineBox<T> (sync) or AsyncPipelineBox<T> (async) from a value or function:
import { Experimental } from '@srhenry/type-utils'
const { pipe } = Experimental
const result = pipe('hello')
.pipe(s => s.toUpperCase())
.pipe(s => s.split(''))
.depipe() // ['H', 'E', 'L', 'L', 'O']When a Promise is passed, the pipeline becomes async:
const result = await pipe(Promise.resolve(42))
.pipe(n => n * 2)
.depipe() // 84Applies a transform function to the boxed value. If the transform returns a Promise, the pipeline auto-promotes to AsyncPipelineBox:
const result = pipe(5)
.pipe(n => n * 10) // PipelineBox<number>
.pipe(n => Promise.resolve(n + 1)) // AsyncPipelineBox<number>
.depipe() // Promise<51>Reverse-apply: calls the boxed function with the given arguments. Replaces the fn => fn(value) lambda pattern:
import { Experimental } from '@srhenry/type-utils'
const { pipe, callWith } = Experimental
const greet = (name: string) => `Hello, ${name}!`
const result = pipe(greet)
.pipe(callWith('World'))
.depipe() // 'Hello, World!'With multi-arg functions:
const add = (a: number, b: number) => a + b
const result = pipe(add)
.pipe(callWith(3, 4))
.depipe() // 7Partial application: curries fn with the given args, returning a transform that applies the next incoming value to the remaining parameters:
import { Experimental } from '@srhenry/type-utils'
const { pipe, apply } = Experimental
const multiply = (a: number, b: number) => a * b
const result = pipe(5)
.pipe(apply(multiply, 3)) // applies 3 as first arg, incoming 5 as second
.depipe() // 15Side-effect factories that pass the value through unchanged. Errors are swallowed by default (swallow: true). Use .catch(handler) to route errors:
const { pipe, tap } = Experimental
const result = pipe('hello')
.pipe(tap(v => console.log(v)))
.pipe(tap(() => { throw new Error('boom') }, { catch: e => console.error(e) }))
.pipe(s => s.toUpperCase())
.depipe() // 'HELLO'Fluent .tap() / .tapAsync() are also available directly on the box:
const result = pipe('hello')
.tap(v => console.log(v))
.pipe(s => s.toUpperCase())
.depipe()Deprecated since v0.8.0 — use
callWith()andapply()instead for clearer, more type-safe transforms.
Creates a dual-callable Pipe<T> — works as both a standalone chainable and a .pipe() transform. When used in a pipeline, the boxed function is called with the incoming value (reverse-apply). When called standalone, it returns its boxed value:
import { Experimental } from '@srhenry/type-utils'
const { enpipe, callWith } = Experimental
const p = enpipe('hello')
p.depipe() // 'hello'
p('unused') // 'hello' (callable)
p.pipe(s => s.toUpperCase()).depipe() // 'HELLO'With partial application:
const curried = enpipe(addUserFactory, db) // curries first arg
curried.depipe() // the curried functionimport { Experimental } from '@srhenry/type-utils'
const { pipe, callWith, apply, tap } = Experimental
const addUserFactory =
(db: Record<string, Record<string, any>[]>) => (user: Record<string, any>) =>
new Promise<string>(resolve => {
setTimeout(() => {
const id = uuid()
db['users'] ??= []
db['users']?.push({ id, ...user })
resolve(id)
}, 200)
})
const addPostFactory =
(db: Record<string, Record<string, any>[]>) => (user_id: string, post: Record<string, any>) =>
new Promise<boolean>(resolve => {
setTimeout(() => {
db['posts'] ??= []
db['posts']?.push({ user_id, ...post })
resolve(true)
}, 300)
})
const db = {
users: [] as Record<string, any>[],
posts: [] as Record<string, any>[],
} as Record<string, Record<string, any>[]>[]
const addPostCurried = (post: Record<string, any>) => (id: string) =>
pipe(addPostFactory)
.pipe(callWith(db))
.pipe(callWith(id, post))
.depipe()
const result = await pipe(addUserFactory)
.pipe(callWith(db))
.pipe(callWith({ name: 'Marcus', email: 'example@email.com' }))
.pipeAsync(addPostCurried({
title: 'Hello World',
content: 'Lorem ipsum dolor sit amet',
}))
.pipeAsync(() => {
if (db['users']!.length === 0 || db['posts']!.length === 0) return false
db['replies'] = []
return true
})
.depipe() // true | false@deprecated since 0.6.2.
Use the new
match()factory instead.
This helper enables you to build switch expressions as it is not available in Javascript vanilla. Each branch allows you to define the matchers or values ahead of time with literal values or inline expressions, or define with callbacks to customize handling of each branch, making it a powerfull way to describe a complex switch without if-else-if language syntax. It defines a lambda as the switch runner, so you can define and run it in the row with more readability.
const switcher = $switch()
.case(4, 'four')
.case(3, 'three')
.case(2, 'two')
.case(1, 'one')
.default('none of the above') // it does not run yet
console.log(switcher.invoke(1)) // one
console.log(switcher.invoke(3)) // three
console.log(switcher.invoke(10)) // none of the aboveconst switcher = $switch(5)
.case(4, 'four')
.case(3, 'three')
.case(2, 'two')
.case(1, 'one')
.default('none of the above') // it does not run yet
console.log(switcher()) // none of the above
console.log(switcher.invoke()) // none of the above
console.log(switcher.invoke(1)) // none of the above
console.log(switcher(3)) // none of the aboveconst switcher = $switch<number>()
.case(
n => n % 2 === 0,
() => Math.floor(Math.random() * 10_000) + 1
)
.default(n => n ** n)
console.log(switcher(1)) // 1 (1^1)
console.log(switcher(2)) // random number between 1-10000
console.log(switcher(3)) // 27 (3^3)
console.log(switcher(4)) // random number between 1-10000
console.log(switcher(5)) // 3125 (5^5)
console.log(switcher(6)) // random number between 1-10000
console.log(switcher(7)) // 823543 (7^7)