@pdfking/tfunc

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

  • iterable The async generator to collect
  • n How many values to collect at most (default: all)

Returns A promise that resolves to an array of the collected values

Example
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

  • func Predicate function that returns true to keep the item, false to filter it out
  • arrays One or more async sequences to filter

Returns An async generator yielding only items that pass the predicate

Example
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

  • arrays One or more async sequences to concatenate

Returns An async generator that yields all values from all sequences in order

Example
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

  • iterable The async sequence to process
  • on_yield Callback invoked for each yielded value (default: no-op)
  • on_stop Callback invoked when iteration completes or errors (default: throws on error)

Returns A promise that resolves when processing is complete

Example
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

  • promises Array or record of promises to wait for

Returns A promise resolving to an array or record of the resolved values

Example
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

  • func Transformation function to apply to each item
  • arrays One or more async sequences to map over

Returns An async generator yielding transformed values

Example
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

  • source The async iterable expected to hold exactly one value

Returns A promise that resolves to that value

Example
import { Only } from "@pdfking/tfunc"

async function* one() {
  yield 1
}

await Only(one()) // 1

Preload

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

  • func Reducer function that takes accumulator, current item, and index
  • sequence The async sequence to reduce
  • initial Initial value for the accumulator

Returns A promise that resolves to the final accumulated value

Example
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); // 10

SafePromise

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

  • promise The promise to wrap

Returns A promise that always resolves with either value or error

Example
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

  • seconds Number of seconds to sleep

Returns A promise that resolves after the specified delay

Example
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

  • input The promise to execute
  • close Cleanup 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

Example
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

  • initial Optional array of initial messages

Returns Object with push, stop, and stream

Example
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

  • initial Optional array of initial messages to send to new subscribers

Returns Object with push, stop, and subscribe methods

Example
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.

Example
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

Example
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

  • func Function to apply to each item (receives item and index)
  • arrays One or more sequences to map over

Returns Generator yielding transformed values

Example
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

Example
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 either

Keys

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

  • obj Object to extract keys from

Returns Array of property names

Example
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

  • func Reducer function (accumulator, item, index) => new accumulator
  • sequence Sequence to reduce
  • initial Initial accumulator value

Returns Final accumulated value

Example
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

  • args Sequences to zip together

Returns Generator yielding tuples of corresponding elements

Example
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

  • entries Iterable of [key, value] pairs

Returns Record object

Example
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

  • obj Object to extract values from

Returns Array of property values

Example
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

  • value A value or array of values

Returns The array unchanged, or a single-item array wrapping the value

Example
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

  • iterable Sequence of items to test
  • func Predicate function to test each item (default: truthiness check)

Returns True if all items satisfy the predicate, false otherwise

Example
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

  • iterable Sequence of items to test
  • func Predicate function to test each item (default: truthiness check)

Returns True if any item satisfies the predicate, false otherwise

Example
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

  • f1 First function in the composition chain

Returns Composed function that applies all functions in sequence

Example
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

  • value The 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

  • value The 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

  • sequence Sequence to deduplicate
  • f Key function returning an Atom (default: Identity)

Returns Generator yielding items with duplicates removed

Example
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

  • obj Object to extract entries from

Returns Array of [key, value] tuples

Example
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

  • valueFn Function to transform values (receives value and key)
  • input Source record object

Returns New record with transformed values, same keys

Example
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

  • sequence Sequence to group
  • func Key function (receives item and index)
  • combiner Optional function to combine each group's items

Returns Record from stringified key to its group (or combined value), in first-seen key order

Example
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

  • guid GUID as either bigint or string

Returns String representation in base-36 format

Example
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

  • obj Source object
  • keys Array of keys to remove

Returns New object without the specified keys

Example
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

  • obj Source object
  • keys Array of keys to include

Returns New object with only the specified keys

Example
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

  • value Array or record to measure

Returns Number of entries

Example
import { Length } from "@pdfking/tfunc"

Length([1, 2, 3]) // 3
Length({ a: 2, b: 3 }) // 2
Length({}) // 0

Partial

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 utility type.

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

  • items Input sequence to partition
  • size Chunk length (must be positive)

Returns Generator yielding arrays of up to size items

Example
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

  • n1 Start value (or end value if n2 is undefined)
  • n2 Optional end value (inclusive)
  • step Step size (default: 1)

Returns Generator yielding numbers in the range

Example
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

  • target The target object to copy to
  • sources The source objects to copy from

Returns The modified target object

Example
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

  • args Records to merge

Returns Merged record with all keys from all inputs

Example
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

  • expr Value to repeat
  • n Number of times to repeat (default: 1)

Returns Generator yielding the repeated value

Example
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

  • sequence Iterable to sort

Returns Sorted array

Example
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

Example
import { GuidToString, UUID } from "@pdfking/tfunc"

UUID() !== UUID() // true (always unique)
GuidToString(UUID()) // its base-36 string

bytes

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

  • value The BigInt to convert

Returns A Uint8Array containing the VLQ-encoded BigInt

Example
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

  • value The boolean to convert

Returns A Uint8Array with a single byte (0 or 1)

Example
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

  • num The number to convert

Returns A Uint8Array containing the 8-byte big-endian float representation

Example
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

  • value The string to convert

Returns A Uint8Array containing the UTF-8 encoded bytes

Example
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

  • value The Uint8Array or ArrayBuffer to decode

Returns The decoded string

Example
import { StringToUInt8, UInt8ToString } from "@pdfking/tfunc"

UInt8ToString(new Uint8Array([72, 101, 108, 108, 111])) // "Hello"

// Round-trip conversion
UInt8ToString(StringToUInt8("Hello, World!")) === "Hello, World!" // true

caches

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

  • func Function to execute once and cache the result

Returns A function that returns the cached result

Example
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

  • data Base64 encoded string

Returns Decoded bytes as Uint8Array

Example
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

  • data URL-safe Base64 encoded string (no padding)

Returns Decoded bytes as Uint8Array

Example
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

  • data Bytes to encode

Returns URL-safe Base64 encoded string (no padding)

Example
import { Base64URLEncode } from "@pdfking/tfunc"

Base64URLEncode(new TextEncoder().encode("Hello World")) // "SGVsbG8gV29ybGQ"
// Safe to use in URLs: /api/data?token=SGVsbG8gV29ybGQ

GUIDToUint8

const GUIDToUint8 = (guid: GUID): Uint8Array

Converts a GUID (256-bit bigint) to a 32-byte Uint8Array. Extracts bytes in big-endian order.

Parameters

  • guid 256-bit identifier as bigint

Returns 32-byte Uint8Array representation

Example
import { GUIDToUint8, UUID } from "@pdfking/tfunc"

GUIDToUint8(UUID()).length // 32

JSONDecode

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

  • stream Async sequence of atomic values (string | number | bigint | boolean)

Returns Promise resolving to GUID hash

Example
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

  • key Secret key as Uint8Array
  • message Message to authenticate as Uint8Array

Returns Promise resolving to GUID hash

Example
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

  • value Any JSON-serializable value

Returns GUID hash

Example
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

  • chunks Async sequence of Uint8Array chunks

Returns Promise resolving to unsigned 32-bit CRC32 value

Example
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

  • handlers Partial map of discriminant values to handler functions
  • fallback Handler for unhandled cases (throws by default)
  • discriminant Field name to use for routing (default: "enum")

Returns Dispatcher function

Example
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>) => Return

Creates 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

  • handlers Complete map of all discriminant values to handlers

Returns Dispatcher function

Example
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 }) // 9

random

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

  • n Number of values to generate
  • min Minimum value (inclusive)
  • max Maximum value (inclusive)
  • seed Random seed for reproducibility (optional, random if not provided)

Returns Iterable of random integers in [min, max]

Example
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 random

RandomChoice

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

  • n Number of items to select
  • choices Array of items to choose from
  • seed Random seed for reproducibility (optional, random if not provided)

Returns Iterator yielding randomly selected items

Example
import { RandomChoice } from "@pdfking/tfunc"

const suits = ["♠", "♥", "♦", "♣"]
Array.from(RandomChoice(5, suits, 42))
// ["♥", "♠", "♦", "♠", "♥"]

Array.from(RandomChoice(5, suits)) // truly random

time

UnixTime

const UnixTime = (date?: Date): Time

Creates a UTC Unix timestamp (seconds since epoch)

Parameters

  • date Optional Date object. If undefined, uses current time

Returns Time branded number representing UTC Unix time

Example
import { UnixTime } from "@pdfking/tfunc"

UnixTime() // 1732118400 (current time)
UnixTime(new Date('2025-01-01T00:00:00Z')) // 1735689600

FromUnixTime

const FromUnixTime = (time?: Time): Date

Converts a Unix timestamp to Date object

Parameters

  • time Optional Time (Unix timestamp in seconds). If undefined, uses current time

Returns Date object

Example
import { FromUnixTime } from "@pdfking/tfunc"

FromUnixTime(1735689600 as Time) // Date: 2025-01-01T00:00:00.000Z
FromUnixTime() // Date: current time

signing

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

  • payload Data to encode in JWT
  • secret Secret key for signing
  • seconds Token validity duration in seconds (default: 3600)
  • current Override current time for testing (optional)

Returns Promise resolving to signed JWT string

Example
import { EncodeJWT } from "@pdfking/tfunc"

EncodeJWT({ userId: 123 }, "secret", 3600)
// "eyJhbGc...header.payload.signature"