UNPKG

@rimbu/deep

Version:

Tools to use handle plain JS objects as immutable objects

198 lines (182 loc) 4.99 kB
import { Arr } from '@rimbu/base'; import type { Update } from '@rimbu/common'; /** * A readonly array of fixed length and types. */ export type Tuple<T extends Tuple.Source> = Readonly<T>; export namespace Tuple { /** * A non-empty readonly array that can serve as a source for a Tuple. */ export type NonEmptySource = readonly [unknown, ...unknown[]]; /** * A readonly array that can serve as a source for a Tuple. */ export type Source = readonly unknown[]; export type IsTuple<T> = T extends { length: infer L } ? 0 extends L ? false : true : false; /** * Returns the indices/keys that are in a tuple. * @typeparam T - the input tuple type */ export type KeysOf<T> = { [K in keyof T]: K }[keyof T & number]; /** * Convenience method to type Tuple types * @param values - the values of the tuple * @example * ```ts * const t = Tuple.of(1, 'a', true) * // type of t => Tuple<[number, string, boolean]> * ``` */ export function of<T extends Tuple.NonEmptySource>(...values: T): Tuple<T> { return values as any; } /** * Returns the item at the given `index` in the givn `tuple`. * @param tuple - the tuple to get the item from * @param index - the index in of the tuple element * @example * ```ts * const t = Tuple.of(1, 'a', true) * console.log(Tuple.getIndex(t, 1)) * // => 'a' * ``` */ export function getIndex<T extends Tuple.Source, K extends keyof T = keyof T>( tuple: T, index: K ): T[K] { return tuple[index]; } /** * Returns the first element of a Tuple. * @param tuple - the source tuple * @example * ```ts * const t = Tuple.of(1, 'a', true) * console.log(Tuple.first(t)) * // => 1 * ``` */ export function first<T extends Tuple.Source>(tuple: T): T[0] { return tuple[0]; } /** * Returns the second element of a Tuple. * @param tuple - the source tuple * @example * ```ts * const t = Tuple.of(1, 'a', true) * console.log(Tuple.second(t)) * // => 'a' * ``` */ export function second<T extends Tuple.Source>(tuple: T): T[1] { return tuple[1]; } /** * Returns the last element of a Tuple. * @param tuple - the source tuple * @example * ```ts * const t = Tuple.of(1, 'a', true) * console.log(Tuple.last(t)) * // => true * ``` */ export function last<T extends readonly unknown[], R>( tuple: readonly [...T, R] ): R { return tuple[tuple.length - 1] as any; } /** * Returns a copy of the given `tuple` where the element at given `index` is updated with the * given `updater`. * @param tuple - the source tuple * @param index - the index in the tuple * @param updater - the updater for the value * @example * ```ts * const t = Tuple.of(1, 'a', true) * console.log(Tuple.updateAt(t, 1, 'b')) * // => [1, 'b', true] * ``` */ export function updateAt<T extends Tuple.Source, K extends keyof T = keyof T>( tuple: T, index: K, updater: Update<T[K]> ): T { return Arr.update(tuple, index as number, updater) as T; } /** * Returns the given `tuple` with the given `values` appended. * @param tuple - the source tuple * @param values - the values to append * @example * ```ts * const t = Tuple.of(1, 'a') * console.log(Tuple.append(t, true, 5)) * // => [1, 'a', true, 5] * ``` */ export function append< T extends Tuple.Source, V extends readonly [unknown, ...unknown[]] >(tuple: T, ...values: V): readonly [...T, ...V] { return [...tuple, ...values]; } /** * Returns a Tuple containing the elements of given `tuple1` followed by the elements * of given `tuple2`. * @param tuple1 - the first Tuple * @param tuple2 - the second Tuple * @example * ```ts * const t1 = Tuple.of(1, 'a') * const t2 = Tuple.of(true, 5) * console.log(Tuple.concat(t1, t2)) * // => [1, 'a', true, 5] * ``` */ export function concat<T1 extends Tuple.Source, T2 extends Tuple.Source>( tuple1: T1, tuple2: T2 ): readonly [...T1, ...T2] { return tuple1.concat(tuple2) as any; } /** * Returns a Tuple containing all but the last element of the given `tuple`. * @param tuple - the source tuple * @example * ```ts * const t = Tuple.of(1, 'a', true) * console.log(Tuple.init(t)) * // => [1, 'a'] * ``` */ export function init<T extends readonly unknown[]>( tuple: readonly [...T, unknown] ): Readonly<T> { return Arr.init(tuple) as any; } /** * Returns a Tuple containing all but the first element of the given `tuple`. * @param tuple - the source tuple * @example * ```ts * const t = Tuple.of(1, 'a', true) * console.log(Tuple.tail(t)) * // => ['a', true] * ``` */ export function tail<T extends readonly [...unknown[]]>( tuple: readonly [unknown, ...T] ): Readonly<T> { return Arr.tail(tuple) as any; } }