UNPKG

rivo

Version:

🤖 The ultimate library you need for composable type-level programming in TypeScript, powered by HKT.

174 lines (165 loc) • 5.28 kB
import type { Call1, Call1W, Fn1 } from "../../HKT"; import type { ValueOf } from "../../Obj/ValueOf"; import type { Eq, Lazied, Lazied$Get } from "../../helpers"; import type { Semigroup } from "../Semigroup"; /** * A type class for types that can be compared. */ export type Monoid = Lazied$Get<MonoidL>; /** * {@link Lazied} version of {@link Monoid}. */ export type MonoidL = Lazied<MonoidImpl[keyof MonoidImpl][0]>; /** * Type class constraints for type class {@link Monoid}. */ export interface TypeClass$$Monoid<T extends Semigroup> { /** * The empty value for the {@link Monoid} instance. */ Empty: T; } /** * Implementations for type class {@link Monoid}. */ export interface MonoidImpl {} /** * Helper type for implementing type class {@link Monoid}. * * @example * ```typescript * import type { Args, Fn, Monoid } from "rivo"; * import type { TypeClass$$Monoid } from "rivo/typeclass"; * * interface StringHolder<S extends string = string> { * value: S; * } * * declare module "rivo/typeclass/Monoid" { * interface MonoidImpl { * StringHolder: ImplMonoidFor<StringHolder, MyType$$Monoid>; * // ^^^^^^^^^^^^ * // Can be any property key * } * } * * interface StringHolder$$Monoid extends TypeClass$$Monoid<StringHolder> { * Empty: StringHolder<"">; * } * ``` */ export type ImplMonoidFor<T extends Semigroup, TypeClass extends TypeClass$$Monoid<T>> = [ T, TypeClass, ]; /** * Helper type for implementing type class {@link Monoid} for generic types. * * @example * ```typescript * import type { Args, Cons, Fn, Lazied, Lazied$Get, Monoid, MonoidL } from "rivo"; * import type { Monoid$GetConstruct, Monoid$GetTypeClass, TypeClass$$Monoid } from "rivo/typeclass"; * * interface Boxed<T> { * value: T; * } * interface BoxedL<L extends Lazied> extends Boxed<Lazied$Get<L>> {} * * declare module "rivo/typeclass/Monoid" { * interface MonoidImpl { * Boxed: ImplMonoidForGeneric<BoxedL<MonoidL>, Boxed$$Monoid$$Relaxer, Boxed$$Monoid$$Builder>; * // ^^^^^^^^^^^^^^^ * // Lazied version of `Boxed` instead of `Boxed<Monoid>` to avoid circular reference error * } * } * * // Used to relax the type of `Monoid` instance to its construct, e.g. `Boxed<42>` -> `Boxed<number>`, * // `Boxed<Boxed<42>>` -> `Boxed<Boxed<number>>`, etc. * interface Boxed$$Monoid$$Relaxer extends Fn<[Boxed<Monoid>], Boxed<Cons<Monoid>>> { * def: ([m]: Args<this>) => Boxed<Monoid$GetConstruct<(typeof m)["value"]>>; * } * * // Used to build type class instance for `Monoid` instance, e.g. `Boxed<42>` -> `Boxed$$Monoid<number>`, * // `Boxed<Boxed<42>>` -> `Boxed$$Monoid<Boxed<number>>`, etc. * interface Boxed$$Monoid$$Builder extends Fn<[Boxed<Cons<Monoid>>], Boxed$$Monoid<Cons<Monoid>>> { * def: ([mCons]: Args<this>) => Boxed$$Monoid<(typeof mCons)["value"]>; * } * * interface Boxed$$Monoid<M extends Cons<Monoid>> extends TypeClass$$Monoid<Boxed<M>> { * Empty: Boxed<Monoid$GetTypeClass<M>["Monoid"]>; * } * * type R = Boxed$$Monoid<string>; * // ^?: Boxed<""> * ``` */ export type ImplMonoidForGeneric< T extends Semigroup, Relaxer extends Fn1<T, T>, TypeClassBuilder extends Fn1<T, TypeClass$$Monoid<T>>, > = [T, Relaxer, TypeClassBuilder]; /** * Get the matching entry of {@link MonoidImpl} for `M`. * @private */ type _Monoid$GetMatch<M extends Monoid> = ValueOf<{ [P in keyof MonoidImpl as M extends MonoidImpl[P][0] ? P : never]: MonoidImpl[P]; }>; /** * Get the construct of `M` from {@link MonoidImpl}. * * @example * ```typescript * type R1 = Monoid$GetConstruct<42>; * // ^?: number * type R2 = Monoid$GetConstruct<[42]>; * // ^?: List<number> * type R3 = Monoid$GetConstruct<[["foo", "bar"], ["baz"]]>; * // ^?: List<List<string>> * ``` */ export type Monoid$GetConstruct<M extends Monoid> = Eq<M, Monoid> extends true ? Monoid : _Monoid$GetMatch<M> extends [infer T, unknown] ? T : _Monoid$GetMatch<M> extends [unknown, infer Relaxer extends Fn1<any, any>, unknown] ? Call1<Relaxer, M> : never; /** * The **unsafe** version of {@link Monoid$GetConstruct} (i.e. no type checking with `M`). */ export type Monoid$GetConstructW<M> = M extends Monoid ? Monoid$GetConstruct<M> : never; /** * Get the type class of `M` from {@link MonoidImpl}. * * @example * ```typescript * type R1 = Monoid$GetTypeClass<42>; * // ^?: Num$$Monoid * type R2 = Monoid$GetTypeClass<[42]>; * // ^?: List$$Monoid<number> * type R3 = Monoid$GetTypeClass<[["foo", "bar"], ["baz"]]>; * // ^?: List$$Monoid<List<string>> * ``` */ export type Monoid$GetTypeClass<M extends Monoid> = ( _Monoid$GetMatch<M> extends [unknown, infer TypeClass] ? TypeClass : _Monoid$GetMatch<M> extends ( [unknown, infer Relaxer extends Fn1<any, unknown>, infer TypeClassBuilder] ) ? Call1W<TypeClassBuilder, Call1<Relaxer, M>> : never ) extends infer R extends { Empty: any } ? R : never; /** * The **unsafe** version of {@link Monoid$GetTypeClass} (i.e. no type checking with `M`). */ export type Monoid$GetTypeClassW<M> = M extends Monoid ? Monoid$GetTypeClass<M> : never; /*********** * Methods * ***********/ /** * Methods for `Monoid`. */ export namespace Monoid {}