Runtime
async
Collect
const Collect = async <T>(iterable: AsyncGenerator<T>, n = POS_INFINITY): Promise<T[]>
Collects an async generator into an array: all of it, or at most the first
n values (fewer if it runs out first). Only what is collected is pulled —
a generator stopped at n stays open, and the next call picks up where this
one stopped.
Parameters
iterableThe async generator to collectnHow many values to collect at most (default: all)
Returns A promise that resolves to an array of the collected values
import { Collect } from "@pdfking/tfunc"
async function* numbers() {
for (let i = 0; i < 5; i++) yield i
}
await Collect(numbers()) // [0, 1, 2, 3, 4]
const gen = numbers()
await Collect(gen, 2) // [0, 1]
await Collect(gen, 2) // [2, 3]FilterAsync
const FilterAsync = async function* <T>( func: (item: T, index: number) => boolean | Promise<boolean>, ...arrays: AsyncSequence<T>[] ): AsyncGenerator<T>
Filters async sequences based on a predicate function. Only items that satisfy the predicate are yielded.
Parameters
funcPredicate function that returns true to keep the item, false to filter it outarraysOne or more async sequences to filter
Returns An async generator yielding only items that pass the predicate
import { FilterAsync } from "@pdfking/tfunc"
async function* numbers() {
yield 1;
yield 2;
yield 3;
yield 4;
}
const evenNumbers = FilterAsync(n => n % 2 === 0, numbers());
for await (const num of evenNumbers) {
console.log(num); // 2, 4
}Join
const Join = async function* <T>(...arrays: AsyncSequence<T>[]): AsyncGenerator<T>
Concatenates multiple async sequences into a single async generator. Values are yielded in order from each sequence.
Parameters
arraysOne or more async sequences to concatenate
Returns An async generator that yields all values from all sequences in order
import { Join } from "@pdfking/tfunc"
async function* gen1() {
yield 1;
yield 2;
}
async function* gen2() {
yield 3;
yield 4;
}
for await (const value of Join(gen1(), gen2())) {
console.log(value); // 1, 2, 3, 4
}SafeIterable
const SafeIterable = <T>(
stream: AsyncSequence<T>,
cleanup: (error: AnyError | undefined) => void = Void
): {
value: AsyncGenerator<T>
error: Promise<AnyError | undefined>
}ProcessIterable
const ProcessIterable = async <T>(
iterable: AsyncSequence<T>,
on_yield: (data: T, index: number) => void = Void,
on_stop: (error: AnyError | undefined) => void = e => {
if (e) throw e
}
): Promise<void>Processes an async iterable, calling callbacks for each yielded value and on completion. Errors are caught and passed to the on_stop callback.
Parameters
iterableThe async sequence to processon_yieldCallback invoked for each yielded value (default: no-op)on_stopCallback invoked when iteration completes or errors (default: throws on error)
Returns A promise that resolves when processing is complete
import { ProcessIterable } from "@pdfking/tfunc"
async function* numbers() {
yield 1;
yield 2;
yield 3;
}
await ProcessIterable(
numbers(),
(value, index) => console.log(`Item ${index}: ${value}`),
(error) => {
if (error) console.error('Error:', error);
else console.log('Done');
}
);WaitPromises
function WaitPromises<T extends Readonly<unknown[]> | []>(
promises: T
): Promise<{ -readonly [K in keyof T]: Awaited<T[K]> }>Waits for all promises to resolve, preserving the input shape. Accepts either an array of promises or a record of promises.
Parameters
promisesArray or record of promises to wait for
Returns A promise resolving to an array or record of the resolved values
import { WaitPromises } from "@pdfking/tfunc"
await WaitPromises([Promise.resolve(1), Promise.resolve("two")])
// [1, "two"]
await WaitPromises({ one: Promise.resolve(1), two: Promise.resolve("two") })
// { one: 1, two: "two" }JoinConcurrent
function JoinConcurrent<T>(...arrays: AsyncGenerator<AsyncGenerator<T>>[]): AsyncGenerator<T>
MapAsync
const MapAsync = async function* <T, N>( func: (item: T, index: number) => N | Promise<N>, ...arrays: AsyncSequence<T>[] ): AsyncGenerator<N>
Maps over async sequences, transforming each item with a function. Items are processed sequentially, one at a time.
Parameters
funcTransformation function to apply to each itemarraysOne or more async sequences to map over
Returns An async generator yielding transformed values
import { MapAsync } from "@pdfking/tfunc"
async function* numbers() {
yield 1;
yield 2;
yield 3;
}
const doubled = MapAsync(n => n * 2, numbers());
for await (const value of doubled) {
console.log(value); // 2, 4, 6
}Only
const Only = async <T>(source: AsyncIterable<T>): Promise<T>
The one value of an async iterable. Throws as soon as a second one shows up (the source is closed there, nothing past it is read), or at the end when there was none.
Parameters
sourceThe async iterable expected to hold exactly one value
Returns A promise that resolves to that value
import { Only } from "@pdfking/tfunc"
async function* one() {
yield 1
}
await Only(one()) // 1Preload
const Preload = <T>(...streams: AsyncSequence<T>[]): AsyncGenerator<T>
ReduceAsync
const ReduceAsync = async <T, A>( func: (accumulator: A, item: T, index: number) => A | Promise<A>, sequence: AsyncSequence<T>, initial: A ): Promise<A>
Reduces an async sequence to a single value using an accumulator function. Processes items sequentially, updating the accumulator with each item.
Parameters
funcReducer function that takes accumulator, current item, and indexsequenceThe async sequence to reduceinitialInitial value for the accumulator
Returns A promise that resolves to the final accumulated value
import { ReduceAsync } from "@pdfking/tfunc"
async function* numbers() {
yield 1;
yield 2;
yield 3;
yield 4;
}
const sum = await ReduceAsync(
(acc, value) => acc + value,
numbers(),
0
);
console.log(sum); // 10SafePromise
const SafePromise = async <T>(promise: Promise<T>): Promise<Result<T>>
Wraps a promise to prevent it from throwing errors. Returns a Result type with either a value or an error, never throws.
Parameters
promiseThe promise to wrap
Returns A promise that always resolves with either value or error
import { SafePromise } from "@pdfking/tfunc"
// Success case
const successResult = await SafePromise(Promise.resolve(42));
console.log(successResult.value); // 42
console.log(successResult.error); // undefined
// Error case
const errorResult = await SafePromise(Promise.reject(new Error("Failed")));
console.log(errorResult.value); // undefined
console.log(errorResult.error?.enum); // "INTERNAL_ERROR"
console.log(errorResult.error?.error?.message); // "Failed"Sleep
const Sleep = (seconds: Time): Promise<void>
Pauses execution for a specified number of seconds. Returns a promise that resolves after the delay.
Parameters
secondsNumber of seconds to sleep
Returns A promise that resolves after the specified delay
import { Sleep } from "@pdfking/tfunc"
console.log('Starting...');
await Sleep(1); // Wait 1 second
console.log('Done!');
// Use in async generators
async function* delayedNumbers() {
yield 1;
await Sleep(0.1);
yield 2;
await Sleep(0.1);
yield 3;
}WithCleanup
const WithCleanup = <T>( input: Promise<T>, close: (error: AnyError | undefined) => void | Promise<void> ): Promise<T>
Executes a promise with guaranteed cleanup callback execution. The cleanup function is called whether the promise succeeds or fails.
Parameters
inputThe promise to executecloseCleanup function called with error (if any) after promise settles
Returns A promise that resolves to the original promise's value
Throws The original error if the promise rejects
import { WithCleanup } from "@pdfking/tfunc"
// Success: cleanup runs, then the value comes through
await WithCleanup(Promise.resolve(42), error => console.log("cleanup, failed:", Boolean(error)))
// cleanup, failed: false
// 42
// Failure: cleanup runs with the error, then the error is rethrown
await WithCleanup(Promise.reject(new Error("Failed")), error =>
console.log("cleanup, failed:", Boolean(error))
).catch(() => "caught")
// cleanup, failed: true
// "caught"classes
Channel
const Channel = <T>(
initial?: T[]
): {
push: (item: T) => void
stop: (error: AnyError | undefined) => void
stream: AsyncGenerator<T>
}Creates a single-consumer async channel. Simpler than Broadcast - only supports one consumer.
Parameters
initialOptional array of initial messages
Returns Object with push, stop, and stream
import { Channel } from "@pdfking/tfunc"
const { push, stop, stream } = Channel<string>()
// Push messages
push("hello")
push("world")
// Stop the channel
stop(undefined)
// Consume messages
for await (const msg of stream) {
console.log(msg) // Outputs: "hello", "world"
}Broadcast
const Broadcast = <T>(
initial?: T[]
): {
push: (item: T) => void
stop: (error: AnyError | undefined) => void
subscribe: () => AsyncGenerator<T>
}Creates a broadcast stream that forwards messages to all active subscribers. Does not maintain memory of past messages - only new subscribers receive future messages. Each subscriber gets their own independent async generator.
Parameters
initialOptional array of initial messages to send to new subscribers
Returns Object with push, stop, and subscribe methods
import { Broadcast } from "@pdfking/tfunc"
const broadcast = Broadcast<string>()
// Subscribe to messages
const sub1 = broadcast.subscribe()
const sub2 = broadcast.subscribe()
// Push messages to all subscribers
broadcast.push("hello")
broadcast.push("world")
// Stop the broadcast
broadcast.stop(undefined)
// Consume messages
for await (const msg of sub1) {
console.log(msg) // Outputs: "hello", "world"
}LockManager
const LockManager = <T = string>()
Creates a lock manager for mutual exclusion on tasks identified by generic keys. Ensures only one task with the same ID executes at a time, queuing others.
import { LockManager } from "@pdfking/tfunc"
const locks = LockManager<string>()
// Manually acquire and release
const release = await locks.acquire("resource-1")
try {
console.log("critical section") // critical section
} finally {
release()
}
// Or use schedule for automatic cleanup
await locks.schedule("resource-1", async () => "done") // "done"ReplayBroadcast
const ReplayBroadcast = <T>(): ReturnType<typeof Broadcast<T>>
Creates a replay broadcast stream that maintains memory of all emitted messages. New subscribers receive all past messages before getting new ones. Similar to Broadcast but with complete message history.
Returns BroadcastInterface with push, stop, and subscribe methods
import { ReplayBroadcast } from "@pdfking/tfunc"
const replay = ReplayBroadcast<string>()
// Push some messages
replay.push("message 1")
replay.push("message 2")
// A new subscriber gets the past messages, then the ones still to come
const sub = replay.subscribe()
replay.push("message 3")
replay.stop(undefined)
for await (const msg of sub) {
console.log(msg) // "message 1", "message 2", "message 3"
}functions
Map
const Map = function* <T, N>( func: (item: T, index: number) => N, ...arrays: Sequence<T>[] ): Generator<N, void, unknown>
Maps a function over one or more sequences, yielding transformed values. Processes multiple sequences sequentially (not in parallel). Generator function for lazy evaluation.
Parameters
funcFunction to apply to each item (receives item and index)arraysOne or more sequences to map over
Returns Generator yielding transformed values
import { Map } from "@pdfking/tfunc"
Array.from(Map(x => x * 2, [1, 2, 3])) // [2, 4, 6]
Array.from(Map((x, i) => `${i}: ${x}`, ["a", "b", "c"])) // ["0: a", "1: b", "2: c"]
// Multiple sequences processed sequentially
Array.from(Map(x => x * 2, [1, 2], [3, 4])) // [2, 4, 6, 8]Void
const Void = (): void
A no-op function that returns void. Useful as a placeholder or default callback.
Returns void
import { Void } from "@pdfking/tfunc"
const loud = false
const onClick = loud ? () => console.log("clicked") : Void
onClick() // does nothing: loud is false
// As a default parameter
const process = (callback: () => void = Void) => callback()
process() // does nothing eitherKeys
const Keys = Object.keys
Returns an array of an object's own enumerable property names. Alias for Object.keys providing a more functional API.
Parameters
objObject to extract keys from
Returns Array of property names
import { Keys } from "@pdfking/tfunc"
const obj = { name: "John", age: 30 }
const keys = Keys(obj) // ["name", "age"]
keys.forEach(key => {
console.log(key)
})Reduce
const Reduce = <T, A>( func: (accumulator: A, item: T, index: number) => A, sequence: Sequence<T>, initial: A ): A
Reduces a sequence to a single value using an accumulator function. Processes items left-to-right, passing accumulator through each step.
Parameters
funcReducer function (accumulator, item, index) => new accumulatorsequenceSequence to reduceinitialInitial accumulator value
Returns Final accumulated value
import { Reduce } from "@pdfking/tfunc"
Reduce((acc, x) => acc + x, [1, 2, 3, 4], 0) // 10
Reduce((acc, x) => acc * x, [1, 2, 3, 4], 1) // 24
Reduce((acc, x, i) => `${acc}${i}: ${x}\n`, ["a", "b"], "") // "0: a\n1: b\n"Zip
const Zip = function* <T extends Sequence<unknown>[]>(
...args: T
): Iterable<{ [K in keyof T]: T[K] extends Sequence<infer U> ? U : never }>Zips multiple sequences together into tuples. Stops when the shortest sequence is exhausted. Type-safe with proper tuple typing.
Parameters
argsSequences to zip together
Returns Generator yielding tuples of corresponding elements
import { Zip } from "@pdfking/tfunc"
const names = ["Alice", "Bob", "Charlie"]
const ages = [25, 30, 35]
const cities = ["NYC", "LA", "CHI"]
Array.from(Zip(names, ages, cities))
// [["Alice", 25, "NYC"], ["Bob", 30, "LA"], ["Charlie", 35, "CHI"]]
// Stops at shortest sequence
Array.from(Zip([1, 2, 3], ["a", "b"]))
// [[1, "a"], [2, "b"]]RecordCreate
function RecordCreate<const E extends Readonly<Readonly<[PropertyKey, unknown]>[]>>(
entries: E
): { [T in E[number] as T[0]]: T[1] }Creates a record object from entries or from separate key and value sequences.
Parameters
entriesIterable of [key, value] pairs
Returns Record object
import { RecordCreate } from "@pdfking/tfunc"
// From entries
RecordCreate([["name", "John"], ["age", 30]] as const)
// { name: "John", age: 30 }
// From separate keys and values
RecordCreate(["name", "age", "city"], ["John", 30, "NYC"])
// { name: "John", age: 30, city: "NYC" }Values
const Values = Object.values
Returns an array of an object's own enumerable property values. Alias for Object.values providing a more functional API.
Parameters
objObject to extract values from
Returns Array of property values
import { Values } from "@pdfking/tfunc"
const obj = { name: "John", age: 30 }
const values = Values(obj) // ["John", 30]
values.forEach(value => {
console.log(value)
})ToArray
const ToArray = <T>(value: T | T[]): T[]
Wraps a value in an array unless it already is one.
Parameters
valueA value or array of values
Returns The array unchanged, or a single-item array wrapping the value
import { ToArray } from "@pdfking/tfunc"
ToArray(1) // [1]
ToArray([1, 2, 3]) // [1, 2, 3]All
const All = <T>(iterable: Sequence<T>, func: (item: T) => boolean = a => !!a)
Tests whether all elements in a sequence satisfy a predicate function. Returns true if all elements pass the test, false otherwise. Default predicate checks truthiness.
Parameters
iterableSequence of items to testfuncPredicate function to test each item (default: truthiness check)
Returns True if all items satisfy the predicate, false otherwise
import { All } from "@pdfking/tfunc"
All([2, 4, 6], x => x % 2 === 0) // true
All([1, 2, 3], x => x % 2 === 0) // false
All([true, 1, "yes"]) // true (all truthy)
All([true, 0, "yes"]) // false (0 is falsy)Any
const Any = <T>(iterable: Sequence<T>, func: (item: T) => boolean = a => !!a)
Tests whether at least one element in a sequence satisfies a predicate function. Returns true if any element passes the test, false otherwise. Default predicate checks truthiness.
Parameters
iterableSequence of items to testfuncPredicate function to test each item (default: truthiness check)
Returns True if any item satisfies the predicate, false otherwise
import { Any } from "@pdfking/tfunc"
Any([1, 3, 5], x => x % 2 === 0) // false
Any([1, 2, 3], x => x % 2 === 0) // true
Any([false, 0, ""]) // false (all falsy)
Any([false, 0, "yes"]) // true ("yes" is truthy)Composition
function Composition<A, B>(f1: (a: A) => B): (a: A) => B
Composes multiple functions into a single function. Functions are applied left-to-right (like pipe, not traditional compose). Type-safe with overloads for up to 9 functions.
Parameters
f1First function in the composition chain
Returns Composed function that applies all functions in sequence
import { Composition } from "@pdfking/tfunc"
const addOne = (x: number) => x + 1
const double = (x: number) => x * 2
const toString = (x: number) => `Result: ${x}`
const process = Composition(addOne, double, toString)
process(5) // "Result: 12" (5 + 1 = 6, 6 * 2 = 12)Constant
const Constant = <T>(value: T): (() => T)
Constant function - takes a value and returns a function that always returns that value
Parameters
valueThe constant value to return
Returns A function that always returns the provided value
Identity
const Identity = <T>(value: T): T
Identity function - returns the input value unchanged
Parameters
valueThe value to return
Returns The same value that was passed in
DeleteDuplicates
const DeleteDuplicates = function* <T>( sequence: Sequence<T>, f: (item: T) => Atom = Identity as (item: T) => Atom ): Generator<T>
Removes duplicates from a sequence, yielding unique items as they appear.
Uses an atomic key function to determine uniqueness. Keeps the first occurrence. Generator function for lazy evaluation.
Parameters
sequenceSequence to deduplicatefKey function returning an Atom (default: Identity)
Returns Generator yielding items with duplicates removed
import { DeleteDuplicates } from "@pdfking/tfunc"
Array.from(DeleteDuplicates([1, 2, 1, 3])) // [1, 2, 3]
Array.from(DeleteDuplicates([{ a: 1 }, { a: 1 }, { a: 2 }], v => v.a)) // [{ a: 1 }, { a: 2 }]Items
const Items = Object.entries
Returns an array of key-value pairs from an object. Alias for Object.entries providing a more functional API.
Parameters
objObject to extract entries from
Returns Array of [key, value] tuples
import { Items } from "@pdfking/tfunc"
const obj = { name: "John", age: 30 }
const entries = Items(obj)
// [["name", "John"], ["age", 30]]
for (const [key, value] of Items(obj)) {
console.log(`${key}: ${value}`)
}RecordMap
const RecordMap = <T extends Record<string, any>, V extends T[keyof T], NV>(
valueFn: (value: V, key: string) => NV,
input: T
): { [K in keyof T]: NV }Maps values of a record while preserving keys. Applies a transformation function to each value.
Parameters
valueFnFunction to transform values (receives value and key)inputSource record object
Returns New record with transformed values, same keys
import { RecordMap } from "@pdfking/tfunc"
RecordMap(v => v * 10, { a: 1, b: 2, c: 3 })
// { a: 10, b: 20, c: 30 }GroupBy
const GroupBy = <T, K extends Atom, N = T[]>( sequence: Sequence<T>, func: (item: T, index: number) => K, combiner?: (items: T[]) => N ): Record<string, N>
Groups items of a sequence by key, optionally combining each group.
Parameters
sequenceSequence to groupfuncKey function (receives item and index)combinerOptional function to combine each group's items
Returns Record from stringified key to its group (or combined value), in first-seen key order
import { GroupBy } from "@pdfking/tfunc"
GroupBy([1, 2, 3, 4], x => (x % 2 === 0 ? "even" : "odd"))
// { odd: [1, 3], even: [2, 4] }
GroupBy([1, 2, 3, 4], x => x % 2, items => items.length)
// { 1: 2, 0: 2 }GuidToString
const GuidToString = (guid: AnyGUID): StringGUID
Converts a GUID to its string representation. If already a string, returns as-is. Otherwise converts bigint to base-36 string.
Parameters
guidGUID as either bigint or string
Returns String representation in base-36 format
import { GuidToString, UUID } from "@pdfking/tfunc"
GuidToString(UUID()) // its base-36 string, e.g. "3h0tsjg9t7viycucd2d2pcr1"
GuidToString("abc123") // "abc123" (unchanged)KeyDrop
const KeyDrop = <T extends object, K extends keyof T>( obj: T, keys: K[] | Sequence<K> ): Omit<T, K>
Creates a new object with specified keys removed. Returns a shallow copy without the specified keys.
Parameters
objSource objectkeysArray of keys to remove
Returns New object without the specified keys
import { KeyDrop } from "@pdfking/tfunc"
const user = { name: "John", age: 30, password: "secret" }
KeyDrop(user, ["password"]) // { name: "John", age: 30 }
KeyDrop(user, ["age", "password"]) // { name: "John" }KeyTake
const KeyTake = <T extends object, K extends keyof T>( obj: T, keys: K[] | Sequence<K> ): Expand<Pick<T, K>>
Creates a new object with only the specified keys. Returns a shallow copy containing only the picked keys.
Parameters
objSource objectkeysArray of keys to include
Returns New object with only the specified keys
import { KeyTake } from "@pdfking/tfunc"
const user = { name: "John", age: 30, password: "secret" }
KeyTake(user, ["name", "age"]) // { name: "John", age: 30 }
KeyTake(user, ["name"] as const) // { name: "John" }Length
const Length = (value: object): number
Counts the entries of an array or the own enumerable keys of a record.
Parameters
valueArray or record to measure
Returns Number of entries
import { Length } from "@pdfking/tfunc"
Length([1, 2, 3]) // 3
Length({ a: 2, b: 3 }) // 2
Length({}) // 0Partial
function Partial<A extends any[], R>(fn: (...args: A) => R): (...args: A) => R
Partially applies arguments to a function.
Uses function overloads for proper type safety.
Note: This is different from TypeScript's built-in Partial
Partition
function* Partition<T>(items: Sequence<T>, size: number): Generator<T[], void, unknown>
Yields successive size-sized chunks from items.
Mirrors Python pyfuncs.utils.functional.list_split(iterable, n).
Parameters
itemsInput sequence to partitionsizeChunk length (must be positive)
Returns Generator yielding arrays of up to size items
import { Partition } from "@pdfking/tfunc"
[...Partition([1, 2, 3, 4, 5], 2)] // [[1, 2], [3, 4], [5]]Range
const Range = function* (n1: number, n2?: number, step = 1)
Generates a sequence of numbers. With one argument: generates 0 to n1-1. With two arguments: generates n1 to n2 (inclusive). Supports custom step size and descending ranges.
Parameters
n1Start value (or end value if n2 is undefined)n2Optional end value (inclusive)stepStep size (default: 1)
Returns Generator yielding numbers in the range
import { Range } from "@pdfking/tfunc"
Array.from(Range(5)) // [0, 1, 2, 3, 4]
Array.from(Range(1, 5)) // [1, 2, 3, 4, 5]
Array.from(Range(0, 10, 2)) // [0, 2, 4, 6, 8, 10]
Array.from(Range(5, 1, -1)) // [5, 4, 3, 2, 1]RecordAssign
const RecordAssign = Object.assign
Copies all enumerable own properties from one or more source objects to a target object. Alias for Object.assign providing a more functional API.
Parameters
targetThe target object to copy tosourcesThe source objects to copy from
Returns The modified target object
import { RecordAssign } from "@pdfking/tfunc"
RecordAssign({ a: 1 }, { b: 2 }, { c: 3 })
// { a: 1, b: 2, c: 3 }RecordMerge
const RecordMerge = <T extends Record<string, unknown>[]>(...args: T): MergeAll<T>
Merges multiple records into one, preserving all keys. Properties from later records override those from earlier ones for duplicate keys.
Parameters
argsRecords to merge
Returns Merged record with all keys from all inputs
import { RecordMerge } from "@pdfking/tfunc"
RecordMerge({ a: 1 }, { b: 2 }) // { a: 1, b: 2 }
RecordMerge({ a: 1, b: 2 }, { b: 3 }) // { a: 1, b: 3 }
RecordMerge({ a: 1 }, { b: 2 }, { c: 3 }) // { a: 1, b: 2, c: 3 }
RecordMerge() // {}Repeat
const Repeat = function* <T>(expr: T, n = 1): Iterable<T>
Generates a sequence by repeating a value n times. Generator function for lazy evaluation.
Parameters
exprValue to repeatnNumber of times to repeat (default: 1)
Returns Generator yielding the repeated value
import { Repeat } from "@pdfking/tfunc"
Array.from(Repeat("x", 3)) // ["x", "x", "x"]
Array.from(Repeat(0, 5)) // [0, 0, 0, 0, 0]
Array.from(Repeat({ id: 1 }, 2)) // [{ id: 1 }, { id: 1 }]SortBy
function SortBy<T extends Atom | Atom[]>(sequence: Sequence<T>): T[]
Sorts sequence by transformer function.
Sorts by single or multiple criteria. Transformer returns Atom or Atom[] for comparison.
Parameters
sequenceIterable to sort
Returns Sorted array
import { SortBy } from "@pdfking/tfunc"
SortBy([4, 3, 2, 1]) // [1, 2, 3, 4]
SortBy([{ a: 2 }, { a: 1 }], x => x.a) // [{ a: 1 }, { a: 2 }]
SortBy([{ a: 1, b: 2 }, { a: 1, b: 1 }], x => [x.a, x.b])UUID
const UUID = (): GUID
Generates a RFC 9562 version 7 UUID: 48-bit big-endian unix millisecond timestamp, then 74 cryptographically random bits, with the version (7) and variant (0b10) markers in place.
Returns UUIDv7 as a 128-bit bigint
import { GuidToString, UUID } from "@pdfking/tfunc"
UUID() !== UUID() // true (always unique)
GuidToString(UUID()) // its base-36 stringbytes
BigIntToUint8
const BigIntToUint8 = (value: bigint): Uint8Array
Converts a BigInt to a Uint8Array using variable-length quantity (VLQ) encoding. Uses ZigZag encoding for negative values to efficiently encode signed integers.
Parameters
valueThe BigInt to convert
Returns A Uint8Array containing the VLQ-encoded BigInt
import { BigIntToUint8, UInt8Hash } from "@pdfking/tfunc"
BigIntToUint8(42n) // Uint8Array([84])
BigIntToUint8(-42n) // Uint8Array([83])
BigIntToUint8(9007199254740991n) // Uint8Array([254, 254, 254, 254, 254, 254, 254, 30])
// Use for hashing
UInt8Hash([BigIntToUint8(12345678901234567890n)])BooleanToUint8
const BooleanToUint8 = (value: boolean): Uint8Array
Converts a boolean to a Uint8Array. True is encoded as 1, false as 0.
Parameters
valueThe boolean to convert
Returns A Uint8Array with a single byte (0 or 1)
import { BooleanToUint8, UInt8Hash } from "@pdfking/tfunc"
BooleanToUint8(true) // Uint8Array([1])
BooleanToUint8(false) // Uint8Array([0])
// Use for hashing
UInt8Hash([BooleanToUint8(true)])NumberToUint8
const NumberToUint8 = (num: number): Uint8Array
Converts a number to a Uint8Array using 64-bit float encoding. Preserves both integer and fractional parts.
Parameters
numThe number to convert
Returns A Uint8Array containing the 8-byte big-endian float representation
import { NumberToUint8, UInt8Hash } from "@pdfking/tfunc"
NumberToUint8(42) // 8 bytes: the big-endian float64
NumberToUint8(3.14159)
NumberToUint8(-42.5)
// Use for hashing
UInt8Hash([NumberToUint8(Date.now())])StringToUInt8
const StringToUInt8 = (value: string): Uint8Array<ArrayBuffer>
Converts a string to a Uint8Array using UTF-8 encoding.
Parameters
valueThe string to convert
Returns A Uint8Array containing the UTF-8 encoded bytes
import { StringToUInt8, UInt8Hash } from "@pdfking/tfunc"
StringToUInt8("Hello") // Uint8Array([72, 101, 108, 108, 111])
// Use for hashing
UInt8Hash([StringToUInt8("my-data")])AtomToUint8
const AtomToUint8 = (value: Atom): Uint8Array
ResizeUInt8
const ResizeUInt8 = async function* ( chunks: AsyncSequence<Uint8Array>, chunk_size: (index: number) => Bytes ): AsyncGenerator<Uint8Array>
UInt8Merge
const UInt8Merge = ( input: BinaryInput | BinaryInput[], bytes?: Bytes ): Uint8Array<ArrayBuffer>
UInt8ToString
const UInt8ToString = (value: Uint8Array | ArrayBuffer): string
Converts a Uint8Array or ArrayBuffer to a string using UTF-8 decoding.
Parameters
valueThe Uint8Array or ArrayBuffer to decode
Returns The decoded string
import { StringToUInt8, UInt8ToString } from "@pdfking/tfunc"
UInt8ToString(new Uint8Array([72, 101, 108, 108, 111])) // "Hello"
// Round-trip conversion
UInt8ToString(StringToUInt8("Hello, World!")) === "Hello, World!" // truecaches
CreateSingleton
const CreateSingleton = <T>(func: () => T): (() => T)
Creates a singleton function that caches the result of the first invocation. Subsequent calls return the cached value without re-executing the function.
Parameters
funcFunction to execute once and cache the result
Returns A function that returns the cached result
import { CreateSingleton } from "@pdfking/tfunc"
const expensiveOperation = () => {
console.log('Computing...');
return 42;
};
const getSingleton = CreateSingleton(expensiveOperation);
console.log(getSingleton()); // Logs: "Computing..." then returns 42
console.log(getSingleton()); // Returns 42 (no log, uses cached value)
console.log(getSingleton()); // Returns 42 (no log, uses cached value)encoding
Base64Decode
const Base64Decode = (data: string): Uint8Array
Decodes a Base64 string to a Uint8Array. Uses the browser's built-in atob function for decoding.
Parameters
dataBase64 encoded string
Returns Decoded bytes as Uint8Array
import { Base64Decode } from "@pdfking/tfunc"
const bytes = Base64Decode("SGVsbG8gV29ybGQ=")
new TextDecoder().decode(bytes) // "Hello World"Base64Encode
const Base64Encode = (data: Uint8Array): string
Base64URLDecode
const Base64URLDecode = (data: string): Uint8Array
Decodes a URL-safe Base64 string to a Uint8Array. Converts URL-safe characters (-_) back to standard Base64 (+/) and adds padding.
Parameters
dataURL-safe Base64 encoded string (no padding)
Returns Decoded bytes as Uint8Array
import { Base64URLDecode } from "@pdfking/tfunc"
const bytes = Base64URLDecode("SGVsbG8gV29ybGQ") // no padding, URL-safe
new TextDecoder().decode(bytes) // "Hello World"Base64URLEncode
const Base64URLEncode = (data: Uint8Array): string
Encodes a Uint8Array to a URL-safe Base64 string. Replaces + with -, / with _, and removes padding (=). Safe for use in URLs and filenames.
Parameters
dataBytes to encode
Returns URL-safe Base64 encoded string (no padding)
import { Base64URLEncode } from "@pdfking/tfunc"
Base64URLEncode(new TextEncoder().encode("Hello World")) // "SGVsbG8gV29ybGQ"
// Safe to use in URLs: /api/data?token=SGVsbG8gV29ybGQGUIDToUint8
const GUIDToUint8 = (guid: GUID): Uint8Array
Converts a GUID (256-bit bigint) to a 32-byte Uint8Array. Extracts bytes in big-endian order.
Parameters
guid256-bit identifier as bigint
Returns 32-byte Uint8Array representation
import { GUIDToUint8, UUID } from "@pdfking/tfunc"
GUIDToUint8(UUID()).length // 32JSONDecode
const JSONDecode = (data: string, options: typeof defaults = defaults)
JSONEncode
const JSONEncode = (data: any, options: Partial<typeof defaults> = defaults)
hashing
Sha256Hasher
const Sha256Hasher = (): Sha256Handle
UInt8Hash
const UInt8Hash = (input: Sequence<Uint8Array>): GUID
AtomHash
const AtomHash = (stream: Sequence<Atom>): GUID
Computes SHA-256 hash of a stream of atomic values.
Converts each atom to bytes and computes a deterministic hash.
Parameters
streamAsync sequence of atomic values (string | number | bigint | boolean)
Returns Promise resolving to GUID hash
import { AtomHash } from "@pdfking/tfunc"
AtomHash(["hello", 42, true])HMACSha256
const HMACSha256 = (key: Uint8Array, message: Uint8Array): GUID
Computes HMAC-SHA256 message authentication code.
Implements RFC 2104 HMAC with SHA-256 hash function.
Parameters
keySecret key as Uint8ArraymessageMessage to authenticate as Uint8Array
Returns Promise resolving to GUID hash
import { HMACSha256 } from "@pdfking/tfunc"
HMACSha256(new Uint8Array([1, 2, 3]), new Uint8Array([4, 5, 6]))JSONHash
const JSONHash = (...value: any): GUID
Computes SHA-256 hash of any JSON-serializable value.
Serializes the value to JSON (with bigint support) then computes hash.
Parameters
valueAny JSON-serializable value
Returns GUID hash
import { JSONHash } from "@pdfking/tfunc"
JSONHash({ name: "John", age: 30 })Uint8Crc32
const Uint8Crc32 = async (chunks: AsyncSequence<Uint8Array>): Promise<number>
Computes CRC32 checksum of byte stream.
Uses standard polynomial 0xEDB88320. Compatible with Python's zlib.crc32.
Parameters
chunksAsync sequence of Uint8Array chunks
Returns Promise resolving to unsigned 32-bit CRC32 value
import { Uint8Crc32 } from "@pdfking/tfunc"
await Uint8Crc32([new Uint8Array([1, 2, 3])])methods
MethodDispatcher
const MethodDispatcher =
<
Args extends [Record<string, unknown>, ...unknown[]],
Return,
DiscriminantKey extends keyof TupleFirst<Args> = "enum",
UnionType extends TupleFirst<Args> = TupleFirst<Args>,
DiscriminantValues extends UnionType[DiscriminantKey] = UnionType[DiscriminantKey],
>(
handlers: Partial<{
[V in DiscriminantValues & (number | string)]: (
item: Extract<UnionType, Record<DiscriminantKey, V>>,
...restArgs: TupleRest<Args>
) => Return
}>,
// Method syntax for bivariance: a fallback typed on the remainder union —
// every member the handlers do not name — is narrower than UnionType, and
// as a strict function type it would be rejected for exactly the arms it
// will never be called with.
fallback: {
bivariance(item: UnionType, ...restArgs: TupleRest<Args>): Return
}["bivariance"] = (
item,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
..._restArgs
) => {
const allowedValues = Keys(handlers)
.map(s => `${s}`)
.join(", ")
throw new Error(
`Unknown ${String(discriminant)}: "${String(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(item as any)[discriminant]
)}". Expected one of: ${allowedValues}.`
)
},
discriminant: DiscriminantKey = "enum" as DiscriminantKey
)Creates a type-safe dispatcher for discriminated union types.
Routes items based on discriminant field (default: "enum") to specific handlers. Supports partial handlers with fallback for unhandled cases.
Parameters
handlersPartial map of discriminant values to handler functionsfallbackHandler for unhandled cases (throws by default)discriminantField name to use for routing (default: "enum")
Returns Dispatcher function
import { MethodDispatcher } from "@pdfking/tfunc"
type Action = { enum: "add", value: number } | { enum: "reset" }
const dispatch = MethodDispatcher<[Action], void>({
add: (action) => console.log(action.value),
reset: () => console.log("reset")
})
dispatch({ enum: "add", value: 5 })FullMethodDispatcher
const FullMethodDispatcher = MethodDispatcher as <
Args extends [Record<string, unknown>, ...unknown[]],
Return,
DiscriminantKey extends keyof TupleFirst<Args> = "enum",
UnionType extends TupleFirst<Args> = TupleFirst<Args>,
DiscriminantValues extends UnionType[DiscriminantKey] = UnionType[DiscriminantKey],
>(
handlers: {
[V in DiscriminantValues & (number | string)]: (
item: Extract<UnionType, Record<DiscriminantKey, V>>,
...restArgs: TupleRest<Args>
) => Return
},
fallback?: (item: UnionType, ...restArgs: TupleRest<Args>) => Return
) => (item: UnionType, ...restArgs: TupleRest<Args>) => ReturnCreates a type-safe dispatcher requiring all cases to be handled.
Like MethodDispatcher but requires exhaustive handlers for all discriminant values. Ensures compile-time safety for complete union coverage.
Parameters
handlersComplete map of all discriminant values to handlers
Returns Dispatcher function
import { FullMethodDispatcher } from "@pdfking/tfunc"
type Shape = { enum: "circle", radius: number } | { enum: "square", side: number }
const area = FullMethodDispatcher<[Shape], number>({
circle: shape => Math.PI * shape.radius ** 2,
square: shape => shape.side ** 2
})
area({ enum: "square", side: 3 }) // 9random
RandomFloat
const RandomFloat = function* ( n: number, min: number, max: number, seed?: number ): IterableIterator<number>
RandomInteger
const RandomInteger = ( n: number, min: number, max: number, seed?: number ): Iterable<number>
Generates pseudo-random integers.
Uses RandomFloat with floor to produce integers in inclusive range [min, max]. Same seed produces same sequence. If no seed provided, uses random seed.
Parameters
nNumber of values to generateminMinimum value (inclusive)maxMaximum value (inclusive)seedRandom seed for reproducibility (optional, random if not provided)
Returns Iterable of random integers in [min, max]
import { RandomInteger } from "@pdfking/tfunc"
Array.from(RandomInteger(10, 1, 6, 123))
// [2, 3, 1, 2, 3, 4, 3, 2, 1, 4]
Array.from(RandomInteger(10, 1, 6)) // truly randomRandomChoice
const RandomChoice = function* <T>( n: number, choices: T[], seed?: number ): IterableIterator<T>
Randomly selects items from array.
Uses RandomInteger to select indices. Same seed produces same choices. If no seed provided, uses random seed.
Parameters
nNumber of items to selectchoicesArray of items to choose fromseedRandom seed for reproducibility (optional, random if not provided)
Returns Iterator yielding randomly selected items
import { RandomChoice } from "@pdfking/tfunc"
const suits = ["♠", "♥", "♦", "♣"]
Array.from(RandomChoice(5, suits, 42))
// ["♥", "♠", "♦", "♠", "♥"]
Array.from(RandomChoice(5, suits)) // truly randomtime
UnixTime
const UnixTime = (date?: Date): Time
Creates a UTC Unix timestamp (seconds since epoch)
Parameters
dateOptional Date object. If undefined, uses current time
Returns Time branded number representing UTC Unix time
import { UnixTime } from "@pdfking/tfunc"
UnixTime() // 1732118400 (current time)
UnixTime(new Date('2025-01-01T00:00:00Z')) // 1735689600FromUnixTime
const FromUnixTime = (time?: Time): Date
Converts a Unix timestamp to Date object
Parameters
timeOptional Time (Unix timestamp in seconds). If undefined, uses current time
Returns Date object
import { FromUnixTime } from "@pdfking/tfunc"
FromUnixTime(1735689600 as Time) // Date: 2025-01-01T00:00:00.000Z
FromUnixTime() // Date: current timesigning
DecodeJWT
const DecodeJWT = <T>(token: string, secret: string): Result<T>
EncodeJWT
const EncodeJWT = <T>( payload: T, secret: string, seconds: number = 3600, current?: Time ): string
Creates signed JWT token using HMAC-SHA256.
Encodes payload as JWT with iat and exp claims. Compatible with standard JWT libraries.
Parameters
payloadData to encode in JWTsecretSecret key for signingsecondsToken validity duration in seconds (default: 3600)currentOverride current time for testing (optional)
Returns Promise resolving to signed JWT string
import { EncodeJWT } from "@pdfking/tfunc"
EncodeJWT({ userId: 123 }, "secret", 3600)
// "eyJhbGc...header.payload.signature"