UNPKG

tiinvo

Version:

A library of types and utilities for your TypeScript and JavaScript projects

609 lines (608 loc) 14.7 kB
/// <reference types="node" /> import type * as Fn from './Fn.js'; /** * Represents a builder (or factory) function. * * It accepts a `Partial<a>` and must return a `a` type. * * @example * * ```ts * import { Functors } from 'tiinvo'; * * export interface User { * name: string; * surname: string; * } * * export type t = User; * * export const make: Functors.Buildable<t> = (p = {}) => ({ * name: p.name ?? '', * surname: p.surname ?? '', * }) * * make() * // { name: '', surname: '' } * * make({ name: 'John' }) * // { name: 'John', surname: '' } * * make({ name: 'John', surname: 'Doe' }) * // { name: 'John', surname: 'Doe' } * ``` * * @group Factories * @since 4.0.0 */ export type Buildable<a> = (a?: Partial<a>) => a; /** * Represents a builder (or factory) module. * * This module must have a `Buildable<a>` function called `make`. * * @example * * ```ts * ////// module User.ts * import { Functors } from 'tiinvo'; * * export interface User { * name: string; * surname: string; * } * * export type t = User; * * export const make: Functors.Buildable<t> = (p = {}) => ({ * name: p.name ?? '', * surname: p.surname ?? '', * }) * * /////// Module Foo.ts * import * as User from './User.ts'; * import { Functors } from 'tiinvo'; * * export const greet = (x: Functors.BuildableMobule<User.t>, y: Partial<ReturnType<Functors.Buildable<User.t>>>) => { * const z = x.make(y); * return `hello ${z.name} ${z.surname}` * } * * greet(User, { name: 'John', surname: 'Doe' }) // "hello John Doe" * greet(User, "" as any) // "hello " * ``` * * @group Factories * @since 4.0.0 */ export type BuildableMobule<a> = { make: Buildable<a>; }; /** * The default value module-like. * * @example * * ```ts * ////// module User.ts * export interface User { * name: string; * surnname: string; * } * * export type t = User; * * export const toString = (t: t) => `hello ${t.name} ${t.surname}`; * * export default { * name: "name", * surname: "surname", * } * * ////// module Animal.ts * export interface Animal { * name: string; * legs: number; * } * * export type t = Animal; * * export const toString = (t: t) => `a ${t.name} has ${t.legs} legs`; * * export default { * name: "raccoon", * legs: 4, * } * * ////// module X.ts * import * as Animal.ts * import * as User.ts * import { Fn, Functors } from 'tiinvo' * * type Stringifiable<a> = Record<'toString', Fn.Unary<a, string>> & Functors.DefaultableModule<a> * const describe = <a>(x: Stringifiable<a>) => x.toString(x.default); * * describe(Animal) // "a raccoon has 4 legs" * describe(User) // "hello name surname" * ``` * * @since 4.0.0 */ export type DefaultableModule<a> = { default: a; }; /** * Is the symbol used to express the presence of an async catchable function * * @since 4.0.0 */ export declare const catchableAsync: unique symbol; /** * Is the symbol used to express the presence of a sync catchable function * * @since 4.0.0 */ export declare const catchableSync: unique symbol; /** * Represents a catchable functor * * @since 4.0.0 */ export type Catchable<f extends Fn.AnyFn> = { catch(error: Error, args: Parameters<f>): ReturnType<f>; func: f; }; /** * Represents a catchable async module functor * * @since 4.0.0 */ export type CatchableAsyncModule<f extends Fn.AnyAsyncFn> = { [catchableAsync](): Catchable<f>; }; /** * Represents a catchable sync module functor * * @since 4.0.0 */ export type CatchableSyncModule<f extends Fn.AnyFn> = { [catchableSync](): Catchable<f>; }; /** * Represents a catchable module functor * * @since 4.0.0 */ export type CatchableModule<f extends Fn.AnyFn> = CatchableAsyncModule<f> | CatchableSyncModule<f>; /** * Is the result of a comparison made by a `Comparable<A>` functor * * - -1 means that a is less than b * - 0 means that a equals to b * - 1 means that a is more than b * * @since 4.0.0 */ export type ComparableResult = -1 | 0 | 1; /** * Is a comparable functor * * @template A is the type of the compared values * @param a the first value to compare * @param b the second value to compare * @return * - -1 means that a is less than b * - 0 means that a equals to b * - 1 means that a is more than b * * @since 4.0.0 */ export type Comparable<A> = { (a: A, b: A): ComparableResult; (a: A): (b: A) => ComparableResult; }; /** * Is a comparable functor module * * @template a is the type of the compared values * @since 4.0.0 */ export type ComparableModule<a> = { cmp: Comparable<a>; }; /** * Is a comparable functor * * @example * * ```ts * import { Functors, Str, Num } from 'tiinvo'; * * module LivingBeen { * export type LivingBeen<A> = { * name: string; * } & A; * * export type T<A> = LivingBeen<A>; * * export const eq = <A>(a: T<A>, b: T<A>): boolean => { * return Str.eq(a.name, b.name); * } * } * * module Animal { * export type Animal = LivingBeen.T<{ * legs: number; * }>; * * export type T = Animal; * * export const make: Functors.Buildable<T> = (p = {}) => ({ * name: p.name ?? '', * legs: p.legs ?? 0, * }) * * export const eq: Functors.Equatable<T> = (a, b) => { * return LivingBeen.eq(a, b) && Num.eq(a.legs, b.legs) * } * } * * module Person { * export type Person = LivingBeen.T<{ * surname: string; * }> * * export type T = Person; * * export const make: Functors.Buildable<T> = (p = {}) => ({ * name: p.name ?? '', * surname: p.surname ?? '', * }) * * export const eq = (a: T, b: T) => { * return LivingBeen.eq(a, b) && Str.eq(a.surname, b.surname) * } * } * * const duck = Animal.make({ legs: 2, name: 'duck' }) * const donaldDuck = Animal.make({ legs: 2, name: 'Donald' }) * const donald = Person.make({ name: 'Donald', surname: 'Duck' }); * * LivingBeen.eq(duck, donaldDuck) // false * LivingBeen.eq(donald, donaldDuck as LivingBeen.T<any>) // true * ``` * * * @template a is the type of the compared values * @param a the first value to compare * @param b the second value to compare * @returns true if a and b are equal * @since 4.0.0 */ export type Equatable<a> = { (a: a, b: a): boolean; (a: a): (b: a) => boolean; }; /** * Is an equatable functor module * * @template a the value type * @since 4.0.0 */ export type EquatableModule<a> = { eq: Equatable<a>; }; /** * Express a function which guards if a passed parameter `x` is of a certain type `a`. * * Read more about typeguards on ts doc pages. * * @example * * ```ts * import { Functors } from 'tiinvo'; * * let is0: Functors.Guardable<0> = (x: unknown): x is 0 => x === 0; * * is0(10) // false * is0("") // false * is0(-1) // false * is0(0) // true * ``` * * @since 4.0.0 */ export type Guardable<a> = (x: unknown) => x is a; /** * Represents a module which have an exported function `guard` of type `Guardable<a>` * * @example * ```ts * import { Fn, Num, Predicate, Functors } from 'tiinvo'; * * module Int8 { * export type T = number; * export const guard = Predicate.and(Num.guard, Num.gte(0), Num.lte(2**8 - 1)) as Functors.Guardable<T>; * } * * module Int16 { * export type T = number; * export const guard = Predicate.and(Num.guard, Num.gte(0), Num.lte(2**16 - 1)) as Functors.Guardable<T>; * } * * const makeeq = <A extends number>(mod: Functors.GuardableModule<A>): Functors.Equatable<A> => { * function eq(a: A, b: A): boolean * function eq(a: A): Fn.Unary<A, boolean> * function eq(a: A, b?: A): any * { * const _eq = (x: A, y: A) => { * return mod.guard(x) && mod.guard(y) && Num.eq(x, y) * } * * if (Num.guard(a) && Num.guard(b)) { * return _eq(a, b) * } * * return (b: A) => _eq(a, b) * } * * return eq; * } * * const eqInt8 = makeeq(Int8) * const eqInt16 = makeeq(Int16) * * eqInt8(255, 255) // true * eqInt8(256, 256) // false * * eqInt16(255, 255) // true * eqInt16(256, 256) // true * ``` * * @since 4.0.0 */ export type GuardableModule<a> = { guard: Guardable<a>; }; /** * The checked type of a Guardable<A> or a GuardableModule<A> * * @example * * ```ts * import type { Functors, Str } from 'tiinvo' * * type x = Functors.GuardReturnType<Str> * * type x: x = "" // ok for the compiler * type y: x = 10 // error for the compiler * ``` * * @group guardables * @since 4.0.0 */ export type GuardReturnType<A extends (Guardable<any> | GuardableModule<any>)> = A extends Guardable<infer U> ? U : A extends GuardableModule<infer U> ? U : never; /** * Returns an array of types from an array of `Guardable<any>` or `GuardableModule<any>` * * @example * * ```ts * import type { Functors, Str, Num, Bool } from 'tiinvo' * * type x: Functors.GuardArrayReturnType<[Str, Num, Bool]> * * const x: x = ["hello", 10, true] // ok for the compiler * const y: x = ["hello", "world", 0] // error for the compiler * ``` * * @group guardables * @since 4.0.0 */ export type GuardArrayReturnType<A extends Array<Guardable<any> | GuardableModule<any>>> = { [key in keyof A]: GuardReturnType<A[key]>; } & RelativeIndexable<any>; /** * Is a filter predicate. * * @since 4.0.0 */ export type Filterable<a> = (a: a) => boolean; /** * * * @since 4.0.0 */ export type FilterableModule<a> = { filter: Filterable<a>; }; /** * A map function. Maps a value `A` to a value `B` * * @template A the starting value * @template B the mapped value * @group Mappables * @since 4.0.0 */ export type Mappable<A, B> = (a: A) => B; /** * A module with a map function `Mappable<A, B>`. * * @example * ```ts * import { Fn, Functors, Num } from 'tiinvo'; * * function makemap<T extends number>(guard: Functors.Guardable<T>, tn: string) { * function map<A>(m: Functors.Mappable<T, A>, t: T): A * function map<A>(m: Functors.Mappable<T, A>): Fn.Unary<T, A> * function map<A>(m: Functors.Mappable<T, A>, t?: T): any * { * const _map = (x: T) => guard(x) ? m(x) : new TypeError("Value not " + tn) * * if (Num.guard(t)) { * return _map(t) * } * * return (b: T) => _map(b) * } * * return map; * } * * module Int8 { * export type T = number; * export const guard = Predicate.and( * Num.guard, * Num.gte(0), * Num.lte(2 ** 8 - 1) * ) as Functors.Guardable<T>; * export const map = makemap(guard, "Int8"); * } * * module Int16 { * export type T = number; * export const guard = Predicate.and( * Num.guard, * Num.gte(0), * Num.lte(2 ** 16 - 1) * ) as Functors.Guardable<T>; * export const map = makemap(guard, "Int16"); * } * * const toHex = <A extends number>( * mod: Functors.MappableModule<A, string>, * a: A, * ) => mod.map(Num.toHex as Functors.Mappable<A, string>, a) * * toHex(Int8, 255) // "0xff" * toHex(Int8, 256) // TypeError("Value not Int8") * * toHex(Int16, 256) // "0x100" * toHex(Int16, 2 ** 16) // TypeError("Value not Int16") * ``` * * @template A the starting value * @template B the mapped value * @group Mappables * @since 4.0.0 */ export type MappableModule<A, B> = { map(m: Mappable<A, B>, a: A): B; map(m: Mappable<A, B>): (a: A) => B; }; /** * Gets the parameter type of a Mappable<any, any> or a MappableModule<any, any> * * @example * * ```ts * import type { Functors } from 'tiinvo' * * type MyMap = (x: string) => number; * type x = Functors.MappableParameter<MyMap> * * let x: x = "hello" // compiler gives ok * // @ts-ignore * let y: x = 10 // compiler gives error * ``` * * @group Mappables * @since 4.0.0 */ export type MappableParameter<A extends (Mappable<any, any> | MappableModule<any, any>)> = A extends Mappable<infer U, any> ? U : A extends MappableModule<infer U, any> ? U : never; /** * Gets the parameters type of an array of `Mappable` or `MappableModule`s. * * @example * * ```ts * import type { Functors } from 'tiinvo' * * type MyMap0 = (x: string) => number; * type MyMap1 = (x: number) => Date; * type x = Functors.MappableParameters<[MyMap0, MyMap1]> * * let x: x = ["hello", 10] // compiler gives ok * // @ts-ignore * let y: x = [10, new Date()] // compiler gives error * ``` * * @group Mappables * @since 4.0.0 */ export type MappableParameters<A extends Array<Mappable<any, any> | MappableModule<any, any>>> = { [key in keyof A]: MappableParameter<A[key]>; } & RelativeIndexable<any>; /** * Gets the returning type of a Mappable<any, any> or a MappableModule<any, any> * * @example * * ```ts * import type { Functors } from 'tiinvo' * * type MyMap = (x: string) => number; * type x = Functors.MappableReturnType<MyMap> * * let x: x = 10 // compiler gives ok * // @ts-ignore * let y: x = "hello" // compiler gives error * ``` * * @group Mappables * @since 4.0.0 */ export type MappableReturnType<A extends (Mappable<any, any> | MappableModule<any, any>)> = A extends Mappable<any, infer U> ? U : A extends MappableModule<any, infer U> ? U : never; /** * Gets the return types of an array of `Mappable` or `MappableModule`s. * * @example * * ```ts * import type { Functors } from 'tiinvo' * * type MyMap0 = (x: string) => number; * type MyMap1 = (x: number) => Date; * type x = Functors.MappableParameters<[MyMap0, MyMap1]> * * let x: x = [10, new Date()] // compiler gives ok * // @ts-ignore * let y: x = ["hello", 10] // compiler gives error * ``` * * @group Mappables * @since 4.0.0 */ export type MappableReturnTypes<A extends Array<Mappable<any, any> | MappableModule<any, any>>> = { [key in keyof A]: MappableReturnType<A[key]>; } & RelativeIndexable<any>; /** * Reduce a value `A` to a value `B` aggregating the previous value `B` to the current. * * @group Mappables * @since 4.0.0 */ export type Reduceable<a, b> = (p: b, c: a) => b; /** * A module with a reduce function exposed. * * @group Mappables * @since 4.0.0 */ export type ReduceableModule<a, b> = { reduce: Reduceable<a, b>; }; /** * Compound module of `ModuleFilterable<a>` and `ModuleMappable<a, b>` * * @since 4.0.0 */ export type FilterMappableModule<a, b> = FilterableModule<a> & { map: Mappable<a, b>; }; /** * Compound module of `ModuleFilterable<a>` and `ModuleMappable<a, b>` with a default value `b`. * * @since 4.0.0 */ export type FilterReduceableModule<a, b> = FilterableModule<a> & ReduceableModule<a, b> & DefaultableModule<b>;