UNPKG

hkt-toolbelt

Version:

Functional and composable type utilities

124 lines (123 loc) 5.01 kB
import { $, Kind, Type } from '..'; /** * `_$if` is a type-level function that evaluates a predicate `Predicate` with * an input `X` of type `Kind._$inputOf<Predicate>`. If the predicate returns * `true`, then `_$if` will return the result of applying `Then` to `X`. * Otherwise, `_$if` will return the result of applying `Else` to `X`. * * This can be thought of as a type-level ternary operator. * * @template Predicate - A type-level function of the form `(x: never) => boolean`. * @template Then - A type-level function that is applied on the truthy branch. * @template Else - A type-level function that is applied on the falsy branch. * @template X - The input to the predicate function. */ export type _$if<Predicate extends Kind.Kind<(x: never) => boolean>, Then extends Kind.Kind, Else extends Kind.Kind, X extends Kind._$inputOf<Predicate>> = $<Predicate, X> extends true ? $<Then, Type._$cast<X, Kind._$inputOf<Then>>> : $<Else, Type._$cast<X, Kind._$inputOf<Else>>>; interface If_T3<Predicate extends Kind.Kind<(x: never) => boolean>, Then extends Kind.Kind, Else extends Kind.Kind> extends Kind.Kind { f(x: Type._$cast<this[Kind._], Kind._$inputOf<Predicate>>): _$if<Predicate, Then, Else, typeof x>; } interface If_T2<Predicate extends Kind.Kind<(x: never) => boolean>, Then extends Kind.Kind> extends Kind.Kind { f(x: Type._$cast<this[Kind._], Kind.Kind>): If_T3<Predicate, Then, typeof x>; } interface If_T1<Predicate extends Kind.Kind<(x: never) => boolean>> extends Kind.Kind { f(x: Type._$cast<this[Kind._], Kind.Kind>): If_T2<Predicate, typeof x>; } /** * `If` is a type-level if-then-else statement. Given a predicate `Predicate`, * a true branch `Then`, and a false branch `Else`, `If` will evaluate the * predicate with an input `X` of type `Kind._$inputOf<Predicate>`. If the * predicate returns `true`, then `If` will return the result of applying * `Then` to `X`. Otherwise, `If` will return the result of applying `Else` * to `X`. * * This can be thought of as a type-level ternary operator. * * @template {Kind} Predicate - A type-level function that returns a boolean. * @template {Kind} Then - A type-level function that is applied when the predicate returns * `true`. * @template {Kind} Else - A type-level function that is applied when the predicate returns * `false`. * @template {InputOf<Predicate>} X - The input to the predicate function. * * ## Usage Examples * * @example * For example, we can use `If` to create a type-level ternary operator. Since * `If` has a high arity, we use `$N` to pipe multiple arguments to `If`. * * Let's implement a function that emits 'yes' if the input string starts with * 'foo', and 'no' otherwise: * * ```ts * import { $, Conditional, Function } from "hkt-toolbelt"; * * type StartsWithFoo = $N< * Conditional.If, * [ * $<String.StartsWith, "foo">, * $<Function.Constant, "yes">, * $<Function.Constant, "no"> * ] * >; * * type Result = StartsWithFoo<"foo">; // "yes" * ``` * * In this example, we use `String.StartsWith` to create a predicate function * that returns `true` if the input string starts with "foo", and `false` * otherwise. * * Each of the truthy and falsy branches are simple constant functions that * return the string "yes" and "no", respectively. These functions are applied * on the input string, so more complex processing can be done in the branches. * * @example * We can also use `If` to filter a list. In this example, we use * `String.StartsWith` to filter out elements of a list that do not start with * the string "foo": * * ```ts * import { $, Conditional, List, String } from "hkt-toolbelt"; * * type Filtered = $< * $< * List.Filter, * $<Conditional.If, $<String.StartsWith, "foo">, String.Identity> * >, * ["foo", "bar", "baz", "foobar"] * >; // ["foo", "foobar"] * ``` * * Here, we use `If` to create a conditional type-level function that returns * `String.Identity` when the string starts with "foo", and `never` otherwise. * We then pass this function to `List.Filter`, which returns a list of only the * elements that satisfy the predicate. */ export interface If extends Kind.Kind { f(x: Type._$cast<this[Kind._], Kind.Kind<(x: never) => boolean>>): If_T1<typeof x>; } /** * Given a predicate, a true branch, and a false branch, return the result of * the if statement. * * @param {Kind.Kind<(x: never) => boolean>} p - The predicate to evaluate. * @param {Kind.Kind} thenClause - The branch to evaluate if the predicate is true. * @param {Kind.Kind} elseClause - The branch to evaluate if the predicate is false. * @param {unknown} x - The input to the predicate. * * @example * ```ts * import { Conditional } from "hkt-toolbelt"; * * const result = Conditional.if( * Conditional.equals('foo') * )( * Function.constant('bar') * )( * Function.identity * )('foo') * // ^? bar * ``` */ declare const _if: Kind._$reify<If>; export { _if as if };