Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/gvergnaud/hotscript

A library of composable functions for the type-level! Transform your TypeScript types in any way you want using functions you already know.
https://github.com/gvergnaud/hotscript

type-level-programming typescript

Last synced: 10 days ago
JSON representation

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

Awesome Lists containing this project

README

        

# 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](https://user-images.githubusercontent.com/9265418/223854503-b54f6a62-9f21-4953-aaa3-5d54699516a7.png)

## 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:

```ts
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](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgBWGApgGjgFQK5gA26AztgMoxTAB2A5mXAHJ4gBG6UJcAvnAGZQIIOACIAFhBgkAxtTAxRAbgBQKmAE8McKKQCMcALwo06ADwq4cAPTWrAPQD8cAGwAmS3ADae7G+wAzNgALAC6mJ5enlb4RKQAdACyAIZgZizsnCTxAIIAJnlmAQB8xdhWFTZ2XsHYAKzYLtgA7KHRuATE2QBSELRmovGiZZWjY1a2YsHxdfEu8c2i7ZTU9NnkRMAwA0Mj4+OTXqLBotiidadiLpeii22VsV1JqWYrtAzxyLoYNIWiesMRod-icznoLmDrmC7u1HgkUmk3mt4jgIBkOFA9hVDnpanBwdg9E18a1YZ0EuRWPtqQc7O5PG1ikogA)

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

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

#### Defining a first-class function

[Run this as a TypeScript Playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgYQIYBt0Bo4DEB2OAKgK5joCmAznAL5wBmUEIcARABYQxUDGUwMDDYBuAFBiA9JLhEOwGgrio4MAJ5gKAWkoA3CunbpUIAEYATVGwCEY4PhgUoDVLwpwAImXTBeqR3AUAB6O+OY0BIhicHBQFDAkUPgAXHAA2jDyVGlsqFAA5gAMbAC6OJkKOXlFpSXitBLqmrHUJOgwAIxwALwoGOgAPKTk1AB0ALKoYANe5L7+FAB8OGkdOABMOADMOAAsJYvi0jEnAHoA-I0a7nFUbTDrPX2YQ95juMYwk9OzPn6Oy3SazgmzgOzg+0OUhkJzgFyAA)

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

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

type result1 = Call, [1, 2, 3, 4]>;
// ^? [[1, 1], [2, 2], [3, 3], [4, 4]]

type result2 = Call, [1, 2, 3, 4]>;
// ^? [1, 1, 2, 2, 3, 3, 4, 4]
```

#### Transforming an object type

[Run this as a TypeScript Playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgBWGApgGjgeQEYBW6AxjAM7YBCEEANugIYB2ZcAvnAGZQQhwBEACwjliUNDH4BuAFAyA9PLgAZdDADkrYr0hl0cMr32cArk1LAILODAg2ozMp2h9mcCIRLwYATwwAuGV8MOAAVCABBZABJZAYfWggGABMAHlCAPjgAXhQ0dFSZODDMIrgAbTLi-CJSMgA6HBBgGEofVOo6RhZ6gFEARxMGWjJUsh8QPDoMjNLi6s86+oiyMmAAcyZUpBA1FIYYBn9EOCZ0AHcAVT0oY5goE30ONlmq3EXyeoBlJgYAa3QAGEGHoACLodBgObzGpeBorNabbZwYDJY5ke7AJjrdgZMoAXRkGVkwX0UWi13QUByYUiMTiCSSaQQZUU8wAegB+Mqo9ETKa0WTFTjAKAYgByDF26Mx2KFcFoIJgkulBll61kL1kbIASmoTFAWIFSWEaSziry1eI5WVdodkgcjiczucAPomG53B5PeUisUwV2-VUY60asqKjGBqXoGWhzVSIA)

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

// Let's compose some functions to transform an object type:
type ToAPIPayload = Pipe<
T,
[
Objects.OmitBy>,
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](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgBWGApgGjgeQEYBW6AxjAM7YDKMUwAdgOYVwDCE4EZ6AMugGYxsAFQCuYADbpmAWQCGMYgAs4AXzh8o7OACJFEcsVpgY2gNwAoczACeGOFCkBWOAF4UadAB5zcOAHo-X18APQB+Hx0-ES4oMj9PYAATAC4yGnoGAD4-SDS4hLpE9AAPZLoREDx0KEztTAiAbQjfalpGMgA6SglgGE9tP21M+qC4UQkpDoAxYHEYas9WjM7qWVgyAHVexX7+zOHmsbFJTrkwb1HfNg4uXgFPJsugpfaOoVoQXe04AB8dWoOTxa6Ve3XEvX6ySGI0uAF1ModAUFxic3hAAKp0YAQOgw3z4IikTpTTQgACidHSUjxuEIJHIHTOADVZOIRFILpc5Aodo8gdylB0tjAdto0m0GHU4OKMkingLFELtv1ypVqlLVVUaodfPDERFYeZMqYgA)

https://user-images.githubusercontent.com/2315749/222081717-96217cd2-ac89-4e06-a942-17fbda717cd2.mp4

```ts
import { Pipe, Objects, Strings, ComposeLeft, Tuples, Match } from "hotscript";

type res5 = Pipe<
// ^? { id: string, index: number }
"/users//posts/",
[
Strings.Split<"/">,
Tuples.Filter>,
Tuples.Map">, 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](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAKjgQwM5wBJwGZQiOAcgAsIZUBjKYMGQgKHoBMBTCgG2ShZwFcA7CjGAR+cAI68WUAJ4BlFuzYxoAHgAqcFgA8YLfk3SoY1fgHMAfAApUi5dABccdQEonAUSUh9MAGJ4QBSUhNXULOAAfOH5ednZGYH49KGxkCh51agIdPQN0DAA6XzEAb3o4CrhuGF4ofgdyyphiYFQAbQAiLjMABg6AXS1dfUM4AAMAEhLE7Gk4AAVuADcAXzgAGimZuYA5HJWxuAB+RorCiY0s9fGpxZZVzZK93QPwhsq4ZtbO7r7BnJG6Em034sygC2WK2uW1Bu32hxOH3Ol1A12BdweU2eMFecHeTRa7S6UF6AyGuVGwO24IxKwcrSsMLBcE8KxcTLmACUWMYDsdTpgChdMqibiVaVNWVNubyxm8BV8ib8yQC8mLqRD7nSAO7EaQsRkg5ms9lGrk8nEIgXIkUgNG3SGS9graUW3H4iqKn4kv7kwHq2Hg1mG4ymMxsjngmWW-lIoUou1iqUlaPuhWE72k-7DNVUwMs51tKahxLh-qRuCpq1x4VXJPO12y+UfL3ErP0FaMGAyMA8TwsbxJfz4IL2KAacIAXkF8xoLA01zaAtt62tBTkJlLqHXYHYwBgqkIRAsq7j6l4u55BQAMmgYKfKoUN2Ht3Jd-vD+tCCe1+fL9v1AgABVfgRH4B8znXTdzFfd8Dw6BwOkiOAOk6ZCOgKJCog6ABiDofzPC8lG3ABBA8egIx8CgAWWQGAKGIVQlw+ONaPo4gCgAdX3RiAGsWBkCBsEwdRqOvftBxgdRkDMHZkG8WiwGuQoAHkACMACtlG3ABxFgD0KAB9ZTRPErwfGk2T5JYRSLEoljBTYhiuJ41RkH4GQTLEiSfAsAV+j8gLGHoChRGMKoeR6OBp0kaR5DsEIoCsDoEA6FwAG56AAeiyliAD0TlC-hwu4VAAEZookKRZFHRLkrANLMpy-LCrC+BSoAJkq2KaoSlQko6JhgCWAoODQVA5O8Rrstyj4CpCtqItQABmbrqvi4J+uSoaljgcJkGm5q5ta4r2p5AAWNa4tqraOjANo6JMfpDtmyp5qKkqeQAViu3rNugbbhrgMACj0XQUDaYhuGwSdCBwwhnoymaWoW06loANl+jax2SnDgCYF6UY+s7UAAdixm6AcG4aHpgJ6HGINArDAPa4FDUQzBcQnjtRz7UAADgpvqqfpVArB22mnuuMAuaRo63pOvmAE4hf+gaJceqB+mlyWtYZpmWfCdnzFlprXoqd7FtKsqopi9bKfVoG3kZsXkFZ0WrDU64KBcWXkZ54L6CAA)
```ts
import * as H from 'hotscript'

declare function querySelector(selector: T): ElementFromSelector | null

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

type ElementFromSelector = H.Pipe,
H.Tuples.Last,
H.Strings.Split<','>,
H.Tuples.ToUnion,
H.Strings.Split<":" | "[" | "." | "#">,
H.Tuples.At<0>,
H.Match<[
H.Match.With>,
H.Match.With
]>
]>
```
![image](https://github.com/gvergnaud/hotscript/assets/633115/d75fe58e-e677-4ead-9cd2-b82a32d0cec7)

## API

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