Skip to content

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

Notifications You must be signed in to change notification settings

pumpncode/hotscript

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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.

About

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

Resources

Code of conduct

Security policy

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

 

Packages

No packages published

Languages

  • TypeScript 97.8%
  • JavaScript 1.6%
  • CSS 0.6%