/hotscript

A library of composable functions for the type-level! Transform your TypeScript types in any way you want using functions you already know.

Primary LanguageTypeScript

Higher-Order TypeScript (HOTScript)

A library of composable functions for the type level!

Transform your TypeScript types in any way you want using functions you already know.

image

Features

  • Type-level higher-order functions (Tuples.Map, Tuples.Filter, Objects.MapValues, etc).
  • Type-level pattern matching with Match.
  • Performant math operations (Numbers.Add, Numbers.Sub, Numbers.Mul, Numbers.Div, etc).
  • Custom "lambda" functions.

🚧 work in progress 🚧

Installation

You can find HotScript on npm:

npm install -D hotscript

HotScript is a work-in-progress library, so expect breaking changes in its API.

Examples

Transforming a list

Run this as a TypeScript Playground

import { Pipe, Tuples, Strings, Numbers } from "hotscript";

type res1 = Pipe<
  //  ^? 62
  [1, 2, 3, 4],
  [
    Tuples.Map<Numbers.Add<3>>,       // [4, 5, 6, 7]
    Tuples.Join<".">,                 // "4.5.6.7"
    Strings.Split<".">,               // ["4", "5", "6", "7"]
    Tuples.Map<Strings.Prepend<"1">>, // ["14", "15", "16", "17"]
    Tuples.Map<Strings.ToNumber>,     // [14, 15, 16, 17]
    Tuples.Sum                        // 62
  ]
>;

Defining a first-class function

Run this as a TypeScript Playground

import { Call, Fn, Tuples } from "hotscript";

// This is a type-level "lambda"!
interface Duplicate extends Fn {
  return: [this["arg0"], this["arg0"]];
}

type result1 = Call<Tuples.Map<Duplicate>, [1, 2, 3, 4]>;
//     ^? [[1, 1], [2, 2], [3, 3], [4, 4]]

type result2 = Call<Tuples.FlatMap<Duplicate>, [1, 2, 3, 4]>;
//     ^? [1, 1, 2, 2, 3, 3, 4, 4]

Transforming an object type

Run this as a TypeScript Playground

import { Pipe, Objects, Booleans } from "hotscript";

// Let's compose some functions to transform an object type:
type ToAPIPayload<T> = Pipe<
  T,
  [
    Objects.OmitBy<Booleans.Equals<symbol>>,
    Objects.Assign<{ metadata: { newUser: true } }>,
    Objects.SnakeCaseDeep,
    Objects.Assign<{ id: string }>
  ]
>;
type T = ToAPIPayload<{
  id: symbol;
  firstName: string;
  lastName: string;
}>;
// Returns:
type T = {
  id: string;
  metadata: { new_user: true };
  first_name: string;
  last_name: string;
};

Parsing a route path

Run this as a TypeScript Playground

hotscript.mp4
import { Pipe, Objects, Strings, ComposeLeft, Tuples, Match } from "hotscript";

type res5 = Pipe<
  //    ^? { id: string, index: number }
  "/users/<id:string>/posts/<index:number>",
  [
    Strings.Split<"/">,
    Tuples.Filter<Strings.StartsWith<"<">>,
    Tuples.Map<ComposeLeft<[Strings.Trim<"<" | ">">, Strings.Split<":">]>>,
    Tuples.ToUnion,
    Objects.FromEntries,
    Objects.MapValues<
      Match<[Match.With<"string", string>, Match.With<"number", number>]>
    >
  ]
>;

Make querySelector typesafe

Run this as a TypeScript Playground

import * as H from 'hotscript'

declare function querySelector<T extends string>(selector: T): ElementFromSelector<T> | null

interface Trim extends H.Fn {
    return:
    this["arg0"] extends `${infer Prev} ,${infer Next}` ?
    H.$<Trim, `${Prev},${Next}`> :
    this["arg0"] extends `${infer Prev}, ${infer Next}` ?
    H.$<Trim, `${Prev},${Next}`> :
    this["arg0"] extends `${infer Prev}:is(${infer El})${infer Rest}` ?
    H.$<Trim, `${Prev}${El}${Rest}`> :
    this["arg0"] extends `${infer Prev}:where(${infer El})${infer Rest}` ?
    H.$<Trim, `${Prev}${El}${Rest}`> :
    this["arg0"] extends `${infer El}(${string})${infer Rest}` ?
    H.$<Trim, `${El}${Rest}`> :
    this["arg0"] extends `${infer El}[${string}]${infer Rest}` ?
    H.$<Trim, `${El}${Rest}`> :
    this["arg0"]
}

type ElementFromSelector<T> = H.Pipe<T, [
    Trim,
    H.Strings.Split<' '>,
    H.Tuples.Last,
    H.Strings.Split<','>,
    H.Tuples.ToUnion,
    H.Strings.Split<":" | "[" | "." | "#">,
    H.Tuples.At<0>,
    H.Match<[
        H.Match.With<keyof HTMLElementTagNameMap, H.Objects.Get<H._, HTMLElementTagNameMap>>,
        H.Match.With<any, HTMLElement>
    ]>
]>

image

API

  • Core
    • Pipe<Input, Fn[]>: Pipes a type through several functions.
    • PipeRight<Fn[], Input>: Pipe a type from right to left.
    • Call<Fn, ...Arg>: Call a type level Fn function.
    • Apply<Fn, Arg[]>: Apply several arguments to an Fn function.
    • PartialApply<Fn, Arg[]>: Make an Fn partially applicable.
    • Compose<Fn[]>: Compose Fn functions from right to left.
    • ComposeLeft<Fn[]>: Compose Fn functions from left to right.
    • args, arg0, arg1, arg2, arg3: Access piped parameters (Useful in combination with Objects.Create).
    • _: Placeholder to partially apply any built-in functions, or functions created with PartialApply.
  • Function
    • ReturnType<FunctionType>: Extract the return type from a function type.
    • Parameters<FunctionType>: Extract the parameters from a function type as a tuple.
    • Parameter<N, FunctionType>: Extract the parameter at index N from a function type.
    • MapReturnType<Fn, FunctionType>: Transform the return type of a function type using an Fn.
    • MapParameters<Fn, FunctionType>: Transform the tuple of parameters of a function type using an Fn.
  • Tuples
    • Create<X> -> [X]: Create a unary tuple from a type.
    • Partition<Fn, Tuple>: Using a predicate Fn, turn a list of types into two lists [Passing[], Rejected[]].
    • IsEmpty<Tuple>: Check if a tuple is empty.
    • Zip<...Tuple[]>: Zips several tuples together. For example. it would turn [[a,b,c], [1,2,3]] into [[a, 1], [b, 2], [c, 3]].
    • ZipWith<Fn, ...Tuple[]>: Zip several tuples by calling a zipper Fn with one argument per input tuple.
    • Sort<Tuple>: Sorts a tuple of number literals.
    • Head<Tuple>: Returns the first element from a tuple type.
    • Tail<Tuple>: Drops the first element from a tuple type.
    • At<N, Tuple>: Returns the Nth element from a tuple.
    • Last<Tuple>: Returns the last element from a tuple.
    • FlatMap<Fn, Tuple>: Calls an Fn function returning a tuple on each element of the input tuple, and flattens all of the returned tuples into a single one.
    • Find<Fn, Tuple>: Finds an element from a tuple using a predicate Fn.
    • Drop<N, Tuple>: Drops the N first elements from a tuple.
    • Take<N, Tuple>: Takes the N first elements from a tuple.
    • TakeWhile<Fn, Tuple>: Take elements while the Fn predicate returns true.
    • GroupBy<Fn, Tuple>: Transform a list into an object containing lists. The Fn function takes each element and returns the key it should be added to.
    • Join<Str, Tuple>: Joins several strings together using the Str separator string.
    • Map<Fn, Tuple>: Transforms each element in a tuple.
    • Filter<Fn, Tuple>: Removes elements from a tuple if the Fn predicate function doesn't return true.
    • Reduce<Fn, Init, Tuple>: Iterates over a tuple a reduce it to a single function using a reducer Fn.
    • ReduceRight<Fn, Init, Tuple>: like Reduce, but starting from the end of the list.
    • Reverse<Tuple>: Reverses the tuple.
    • Every<Fn, Tuple>: Checks if all element passes the Fn predicate.
    • Some<Fn, Tuple>: Checks if at least one element passes the Fn predicate.
    • SplitAt<N, Tuple>: Split a tuple into a left and a right tuple using an index.
    • ToUnion<Tuple>: Turns a tuple into a union of elements.
    • ToIntersection<Tuple>: Turns a tuple into an intersection of elements.
    • Prepend<X, Tuple>: Adds a type at the beginning of a tuple.
    • Append<X, Tuple>: Adds a type at the end of a tuple.
    • Concat<T1, T2>: Merges two tuples together.
    • Min<Tuple>: Returns the minimum number in a list of number literal types.
    • Max<Tuple>: Returns the maximum number in a list of number literal types.
    • Sum<Tuple>: Add all numbers in a list of number literal types together.
  • Object
    • Readonly<Obj>: Makes all object keys readonly.
    • Mutable<Obj>: Removes readonly from all object keys.
    • Required<Obj>: Makes all keys required.
    • Partial<Obj>: Makes all keys optional.
    • ReadonlyDeep<Obj>: Recursively makes all object keys readonly.
    • MutableDeep<Obj>: Recursively removes readonly from all object keys.
    • RequiredDeep<Obj>: Recursively makes all keys required.
    • PartialDeep<Obj>: Recursively makes all keys optional.
    • Update<Path, Fn | V, Obj>: Immutably update an object's field under a certain path. Paths are dot-separated strings: a.b.c.
    • Record<Key, Value>: Creates an object type with keys of type Key and values of type Value.
    • Keys<Obj>: Extracts the keys from an object type Obj.
    • Values<Obj>: Extracts the values from an object type Obj.
    • AllPaths<Obj>: Extracts all possible paths of an object type Obj.
    • Create<Pattern, X>: Creates an object of type Pattern with values of type X.
    • Get<Path, Obj>: Gets the value at the specified path Path in the object Obj.
    • FromEntries<[Key, Value]>: Creates an object from a union of key-value pairs.
    • Entries<Obj>: Extracts the union of key-value pairs from an object type Obj.
    • MapValues<Fn, Obj>: Transforms the values of an object type Obj using a mapper function Fn.
    • MapKeys<Fn, Obj>: Transforms the keys of an object type Obj using a mapper function Fn.
    • Assign<...Obj>: Merges multiple objects together.
    • Pick<Key, Obj>: Picks specific keys Key from an object type Obj.
    • PickBy<Fn, Obj>: Picks keys from an object type Obj based on a predicate function Fn.
    • Omit<Key, Obj>: Omits specific keys Key from an object type Obj.
    • OmitBy<Fn, Obj>: Omits keys from an object type Obj based on a predicate function Fn.
    • CamelCase<Obj>: Converts the keys of an object type Obj to camelCase.
    • CamelCaseDeep<Obj>: Recursively converts the keys of an object type Obj to camelCase.
    • SnakeCase<Obj>: Converts the keys of an object type Obj to snake_case.
    • SnakeCaseDeep<Obj>: Recursively converts the keys of an object type Obj to snake_case.
    • KebabCase<Obj>: Converts the keys of an object type Obj to kebab-case.
    • KebabCaseDeep<Obj>: Recursively converts the keys of an object type Obj to kebab-case.
  • Union
    • Map<Fn, U>: Transforms each member of a union type U using a mapper function Fn.
    • Extract<T, U>: Extracts the subset of a union type U that is assignable to type T.
    • ExtractBy<Fn, U>: Extracts the subset of a union typeUthat satisfies the predicate function Fn.
    • Exclude<T, U>: Excludes the subset of a union typeUthat is assignable to type T.
    • ExcludeBy<Fn, U>: Excludes the subset of a union typeUthat satisfies the predicate function Fn.
    • NonNullable<U>: Removes null and undefined from a union type U.
    • ToTuple<U>: Converts a union typeUto a tuple type.
    • ToIntersection<U>: Converts a union typeUto an intersection type.
  • String
    • Length<Str>: Returns the length of a string type Str.
    • TrimLeft<Char, Str>: Removes the specified character from the left side of a string type Str.
    • TrimRight<Char, Str>: Removes the specified character from the right side of a string type Str.
    • Trim<Char, Str>: Removes the specified character from both sides of a string type Str.
    • Join<Sep, Str>: Joins multiple string type Str with a separator Sep.
    • Replace<From, To, Str>: Replaces all occurrences of a substring From with another substring To in a string type Str.
    • Slice<Start, End, Str>: Extracts a portion of a string type Str from index Start to index End.
    • Split<Sep, Str>: Splits a string type Str into a tuple of substrings using a separator Sep.
    • Repeat<N, Str>: Repeats a string type Str N times.
    • StartsWith<S, Str>: Checks if a string type Str starts with a substring S.
    • EndsWith<E, Str>: Checks if a string type Str ends with a substring E.
    • ToTuple<Str>: Converts a string type Str to a tuple type.
    • ToNumber<Str>: Converts a string type Str to a number type.
    • ToString<T>: Converts any literal type T to a string literal type.
    • Prepend<Start, Str>: Prepends a string type Start to the beginning of a string type Str.
    • Append<End, Str>: Appends a string type End to the end of a string type Str.
    • Uppercase<Str>: Converts a string type Str to uppercase.
    • Lowercase<Str>: Converts a string type Str to lowercase.
    • Capitalize<Str>: Capitalizes the first letter of a string type Str.
    • Uncapitalize<Str>: Converts the first letter of a string type Str to lowercase.
    • SnakeCase<Str>: Converts a string type Str to snake_case.
    • CamelCase<Str>: Converts a string type Str to camelCase.
    • KebabCase<Str>: Converts a string type Str to kebab-case.
    • Compare<Str1, Str2>: Compares two string types Str1 and Str2 and returns a number indicating their relative order.
    • Equal<Str1, Str2>: Checks if two string types Str1 and Str2 are equal.
    • NotEqual<Str1, Str2>: Checks if two string types Str1 and Str2 are not equal.
    • LessThan<Str1, Str2>: Checks if Str1 is less than Str2 in lexicographical order.
    • LessThanOrEqual<Str1, Str2>: Checks if Str1 is less than or equal to Str2 in lexicographical order.
    • GreaterThan<Str1, Str2>: Checks if Str1 is greater than Str2 in lexicographical order.
    • GreaterThanOrEqual<Str1, Str2>: Checks if Str1 is greater than or equal to Str2 in lexicographical order.
  • Number
    • Add<N, M>: Adds two number types N and M.
    • Multiply<N, M>: Multiplies two number types N and M.
    • Subtract<N, M>: Subtracts the number type M from N.
    • Negate<N>: Negates a number type N by changing its sign.
    • Power<N, M>: Raises a number type N to the power of M.
    • Div<N, M>: Divides a number type N by M.
    • Mod<N, M>: Calculates the remainder of dividing a number type N by M.
    • Abs<N>: Returns the absolute value of a number type N.
    • Compare<N, M>: Compares two number types N and M and returns a number indicating their relative order.
    • GreaterThan<N, M>: Checks if the number type N is greater than M.
    • GreaterThanOrEqual<N, M>: Checks if the number type N is greater than or equal to M.
    • LessThan<N, M>: Checks if the number type N is less than M.
    • LessThanOrEqual<N, M>: Checks if the number type N is less than or equal to M.
  • Boolean
    • And<Bool1, Bool2>: Performs a logical AND operation between two boolean types Bool1 and Bool2.
    • Or<Bool1, Bool2>: Performs a logical OR operation between two boolean types Bool1 and Bool2.
    • XOr<Bool1, Bool2>: Performs a logical XOR (exclusive OR) operation between two boolean types Bool1 and Bool2.
    • Not<Bool>: Performs a logical NOT operation on a boolean type Bool.
    • Extends<A, B>: Checks if type A extends or is equal to type B.
    • Equals<A, B>: Checks if type A is equal to type B.
    • DoesNotExtend<A, B>: Checks if type A does not extend type B.