API Reference

Complete reference for all kotlinify-ts functions and types

⚠️

Enable Prototype Extensions for Method Chaining

Examples showing method chaining syntax (like .let(), .apply()) require importing from the main package:

import 'kotlinify-ts'
import { let, apply } from 'kotlinify-ts'

Alternative: Use function form syntax without the main import (both forms shown in examples below).

Scope Functions

let<T, R>(value: T, block: (value: T) => R): R

Calls the specified function block with the given value as its argument and returns its result.

import 'kotlinify-ts'
import { let } from 'kotlinify-ts';

// Method chaining syntax
const processedData = fetchData()
  .let(data => JSON.parse(data))
  .let(obj => obj.items)
  .let(items => items.filter(x => x.active))
  .let(active => active.map(x => x.name));

// Function form (no main import needed)
const upperName = let({ name: "Alice" }, u => u.name.toUpperCase());

// Null-safe navigation
const email = fetchUser(id)
  ?.let(user => user.profile)
  ?.let(profile => profile.email)
  ?? "no-email@example.com";

apply<T>(value: T, block: (value: T) => void): T

Calls the specified function block with the given value as its receiver and returns the value.

import { apply } from 'kotlinify-ts';

// Builder pattern - configure and return the same object
const canvas = document.createElement('canvas')
  .apply(el => {
    el.width = 800;
    el.height = 600;
    el.className = "game-canvas";
  })
  .apply(el => document.body.appendChild(el));

// Configure complex objects inline
const request = new XMLHttpRequest()
  .apply(xhr => {
    xhr.open('POST', '/api/data');
    xhr.setRequestHeader('Content-Type', 'application/json');
  })
  .also(xhr => xhr.send(JSON.stringify(data)));

also<T>(value: T, block: (value: T) => void): T

Calls the specified function block with the given value as its argument and returns the value.

import { also } from 'kotlinify-ts';

// Debug values in a chain without breaking the flow
const processed = fetchUser(id)
  .let(user => user.orders)
  .also(orders => console.log("Found orders:", orders.length))
  .let(orders => orders.filter(o => o.status === "pending"))
  .also(pending => console.log("Pending:", pending.length))
  .let(pending => pending.map(o => o.total));

// Validation and logging
const savedUser = createUser(data)
  .also(user => validateUser(user))
  .also(user => logger.info("Created user:", user.id))
  .also(user => cache.set(user.id, user));

run<T, R>(value: T, block: function(): R): R

Calls the specified function block with the given value as this context and returns its result.

import { run } from 'kotlinify-ts';

const sum = run({ x: 3, y: 4 }, function() {
  return this.x + this.y;
});
// 7

// Chaining with prototype method
const area = { width: 10, height: 5 }
  .run(function() { return this.width * this.height; })
  .let(x => x * 2);
// 100

withValue<T, R>(receiver: T, block: function(): R): R

Calls the specified function block with the given value as this context and returns its result. Similar to run but with different parameter order.

import { withValue, also } from 'kotlinify-ts';

const area = withValue({ width: 10, height: 5 }, function() {
  return this.width * this.height;
});
// 50

// Chaining multiple operations
also(
  withValue({ x: 5, y: 10 }, function() { return this.x * this.y; }),
  result => console.log("Product:", result)
);

Null Safety

takeIf<T>(value: T, predicate: (value: T) => boolean): T | undefined

Returns the value if it satisfies the given predicate, otherwise undefined.

import { takeIf } from 'kotlinify-ts/nullsafety';

const positive = takeIf(42, x => x > 0);
// 42

const negative = takeIf(-5, x => x > 0);
// undefined

takeUnless<T>(value: T, predicate: (value: T) => boolean): T | undefined

Returns the value if it does not satisfy the given predicate, otherwise undefined.

import { takeUnless } from 'kotlinify-ts/nullsafety';

const valid = takeUnless("hello", str => str.length === 0);
// "hello"

isNullOrEmpty(value: string | T[] | null | undefined): boolean

Returns true if the value is null, undefined, or has length 0.

import { isNullOrEmpty } from 'kotlinify-ts/nullsafety';

isNullOrEmpty("");
// true

isNullOrEmpty([]);
// true

isNullOrEmpty("hello");
// false

isNullOrBlank(value: string | null | undefined): boolean

Returns true if the value is null, undefined, or contains only whitespace.

import { isNullOrBlank } from 'kotlinify-ts/nullsafety';

isNullOrBlank("   ");
// true

isNullOrBlank("hello");
// false

Collections

first<T>(array: T[], predicate?: (value: T) => boolean): T

Returns the first element, or the first element matching the predicate. Throws if not found.

import { first } from 'kotlinify-ts/collections';

first([1, 2, 3]);
// 1

first([1, 2, 3], x => x > 1);
// 2

groupBy<T, K>(array: T[], keySelector: (value: T) => K): Map<K, T[]>

Groups elements by the key returned by the given keySelector function. Returns a Map for type safety.

import { groupBy } from 'kotlinify-ts/collections';

const groups = groupBy(
  [{ age: 20 }, { age: 30 }, { age: 20 }],
  x => x.age
);
// Map { 20 => [{ age: 20 }, { age: 20 }], 30 => [{ age: 30 }] }

// Access groups using Map methods
groups.get(20); // [{ age: 20 }, { age: 20 }]

// Iterate over groups
for (const [age, items] of groups) {
  console.log(`Age ${age}: ${items.length} items`);
}

partition<T>(array: T[], predicate: (value: T) => boolean): [T[], T[]]

Splits the array into a pair of lists, where the first list contains elements matching the predicate and the second contains elements not matching.

import { partition } from 'kotlinify-ts/collections';

partition([1, 2, 3, 4, 5], x => x % 2 === 0);
// [[2, 4], [1, 3, 5]]

chunked<T>(array: T[], size: number): T[][]

Splits the array into arrays of the given size.

import { chunked } from 'kotlinify-ts/collections';

chunked([1, 2, 3, 4, 5, 6, 7], 3);
// [[1, 2, 3], [4, 5, 6], [7]]

windowed<T>(array: T[], size: number, step?: number): T[][]

Returns a list of sliding windows of the given size with the given step.

import { windowed } from 'kotlinify-ts/collections';

windowed([1, 2, 3, 4, 5], 3, 1);
// [[1, 2, 3], [2, 3, 4], [3, 4, 5]]

distinctBy<T, K>(array: T[], selector: (value: T) => K): T[]

Returns a list containing only elements with distinct keys returned by the selector.

import { distinctBy } from 'kotlinify-ts/collections';

distinctBy(
  [{ id: 1, name: "A" }, { id: 2, name: "B" }, { id: 1, name: "C" }],
  x => x.id
);
// [{ id: 1, name: "A" }, { id: 2, name: "B" }]

Sequences

class Sequence<T>

A lazy evaluated collection that performs operations only when terminal operations are called.

import { asSequence } from 'kotlinify-ts/sequences';

asSequence([1, 2, 3, 4, 5])
  .filter(x => x % 2 === 0)
  .map(x => x * x)
  .toArray();
// [4, 16]

sequenceOf<T>(...elements: T[]): Sequence<T>

Creates a sequence from the given elements.

import { sequenceOf } from 'kotlinify-ts/sequences';

sequenceOf(1, 2, 3, 4, 5)
  .take(3)
  .toArray();
// [1, 2, 3]

generateSequence<T>(seed: T, nextFunction: (current: T) => T | null): Sequence<T>

Creates an infinite sequence starting with seed and continuing with values generated by nextFunction.

import { generateSequence } from 'kotlinify-ts/sequences';

generateSequence(1, x => x + 1)
  .take(5)
  .toArray();
// [1, 2, 3, 4, 5]

Monads

class Option<T>

Represents a value that may or may not exist. Use Some for values and None for absence.

import { Option, Some, None, fromNullable } from 'kotlinify-ts/monads';

fromNullable(findUser(id))
  .map(user => user.email)
  .getOrElse("No email");

class Either<L, R>

Represents a value that is either Left (failure) or Right (success).

import { Either, Left, Right } from 'kotlinify-ts/monads';

function divide(a: number, b: number): Either<string, number> {
  return b === 0 ? Left("Division by zero") : Right(a / b);
}

divide(10, 2)
  .map(x => x * 2)
  .fold(
    error => console.error(error),
    result => console.log(result)
  );

class Result<T, E>

Wraps operation outcomes with detailed success or failure information.

import { Result, tryCatch } from 'kotlinify-ts/monads';

tryCatch(() => JSON.parse(data))
  .map(obj => obj.value)
  .onSuccess(value => console.log(value))
  .onFailure(error => console.error(error))
  .getOrElse(defaultValue);

Flow

class Flow<T>

A cold asynchronous stream that emits values sequentially.

import { flow } from 'kotlinify-ts/flow';

const numbersFlow = flow(async function*() {
  for (let i = 0; i < 10; i++) {
    yield i;
  }
});

numbersFlow
  .filter(x => x % 2 === 0)
  .map(x => x * x)
  .collect(x => console.log(x));

class StateFlow<T>

A hot flow that represents a state with a current value.

import { MutableStateFlow } from 'kotlinify-ts/flow';

const counter = new MutableStateFlow(0);

counter.collect(value => console.log("Count:", value));

counter.emit(1);
counter.emit(2);

class SharedFlow<T>

A hot flow that shares emitted values among multiple collectors.

import { MutableSharedFlow } from 'kotlinify-ts/flow';

const events = new MutableSharedFlow({ replay: 1 });

events.collect(event => console.log("Subscriber 1:", event));
events.collect(event => console.log("Subscriber 2:", event));

events.emit("Event A");

Coroutines

launch(block: (this: Job) => void | Promise<void>): Job

Launches a new coroutine without blocking the current thread and returns a Job.

import { launch, delay } from 'kotlinify-ts/coroutines';

const job = launch(async function() {
  await delay(1000);
  console.log("Done!");
});

job.cancel();

async<T>(block: () => Promise<T>): Deferred<T>

Creates a coroutine and returns a Deferred that represents its future result.

import { async } from 'kotlinify-ts/coroutines';

const deferred = async(async () => {
  return fetchData();
});

const result = await deferred.await();

withTimeout<T>(timeoutMs: number, block: () => Promise<T>): Promise<T>

Runs the given block with a timeout. Throws TimeoutError if the timeout is exceeded.

import { withTimeout } from 'kotlinify-ts/coroutines';

const result = await withTimeout(5000, async () => {
  return await fetchData();
});

Channels

class Channel<T>

A concurrent communication primitive for sending and receiving values between coroutines.

import { Channel } from 'kotlinify-ts/channels';

const channel = new Channel<number>();

await channel.send(1);
await channel.send(2);
channel.close();

for await (const value of channel) {
  console.log(value);
}

produce<T>(block: (channel: SendChannel<T>) => Promise<void>): ReceiveChannel<T>

Creates a coroutine that produces values and sends them to a channel.

import { produce } from 'kotlinify-ts/channels';

const numbers = produce(async (channel) => {
  for (let i = 0; i < 10; i++) {
    await channel.send(i);
  }
});

for await (const num of numbers) {
  console.log(num);
}

Next Steps