import * as fun from "https://deno.land/x/fun@v2.0.0/kind.ts";
Kind is a collection of types used for doing something called Type Substitution. The core idea here is that sometimes there is a function that is generic at two levels, at the concrete type as well as at the type leve. A simple example of this is a forEach function. In javascript the built in Array and Set data structures both have a built in forEach method. If we look at Array and Set we can see that the creation functions are similar.
const arr = new Array<number>()
returns Array;const set = new Set<number>()
returns Set;
If we look at the type signitures on forEach for arr
and set
we also
notice a similar pattern.
type A = (typeof arr)['forEach']
returns(callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any) => void
type B = (typeof set)['forEach']
returns(callbackfn: (value: number, value2: number, set: Set<number>) => void, thisArg?: any) => void
Both forEach methods have the same concrete value of number
but differ in
that they operate over an Array or a Set. Here is a table to illustrate this
pattern a bit more clearly.
Structure | Outer Type | Inner Type | forEach Type |
---|---|---|---|
Array | Array | A | (value: A, index: number, struct: A[]) => void |
Set | Set | A | (value: A, index: number, struct: Set) => void |
Map<K, V> | Map | K (key), V (value) | (value: V, key: K, struct: Map<K, V>) => void |
In general we can see that the forEach function could have a more generic type signiture like this:
type ForEach<Outer> = {
forEach: <K, V>(struct: Outer<K, V>) => (value: V, key: K, struct: Outer<K, V>) => void;
}
Unfortunately, while these types of patterns are abundant within TypeScript (and most programming languages). The ability to pass generic types around and fill type holes is not built into TypeScript. However, with some type magic we can create our own type level substitutions using methods pionered by gcanti in fp-ts.
Interfaces
I Fix | Fix a concrete type as a non-substituting Kind. This allows one to define algebraic structures over things like number, string, etc. |
I Hold | The Hold interface allows one to trick the typescript compiler into holding onto type information that it would otherwise discard. This is useful when creating an interface that merges multiple type classes (see Flatmappable). |
I Kind | Kind is an interface that can be extended to retrieve inner types using "this". |
Type Aliases
T $ | $ is an alias of Substitute, lifting out, in, and inout substitutions to positional type parameters. |
An extension type to be used to constrain in input to an outer container with any concrete types. | |
T In | Access the Premappable substitution type at index N |
Access the Invariant substitution type at index N | |
A type level utility that turns a type union into a type intersection. This type is dangerous and can have unexpected results so extra runtime testing is necessary when used. | |
T Out | Access the Covariant substitution type at index N |
Spread the keys of a struct union into a single struct. | |
Substitute is a substitution type, taking a Kind implementation T and substituting it with types passed in S. | |
The Substitutions type splits the different type level substitutions into tuples based on variance. |