A higher-kinded-type companion to ts-toolbelt
Higher-kinded types are encoded as a type that extends the Kind
type. The Kind
type is a generic that takes in a type parameter
All higher-kinded types possess a property called Kind._
, which is a symbol that represents the unapplied type parameter.
namespace Kind {
export type _ = unique symbol;
}
declare abstract class Kind<F extends Function.Function = Function.Function> {
abstract readonly [Kind._]: unknown;
f: F;
}
A HK-type is defined via an interface that extends the Kind
type.
interface Length extends Kind.Kind {
f(x: Type._$cast<this[Kind._], unknown[]>): typeof x["length"];
}
We encode the higher-kinded type parameter via this
. We can further use the Type._$cast
generic to encode input constraints.
Finally, we can apply a higher-kinded type to a type argument via the $
generic.
export type $<F extends Kind.Kind, X> =
Function._$returnType<
(F & { readonly [Kind._]: Type._$cast<X, Kind._$inputOf<F>> })['f']
>
Here, we use the Kind._$inputOf
and Type._$cast
types to extract and constrain the input type of the higher-kinded type Function._$returnType
generic to extract the return type of the higher-kinded type, after we have used &
to merge the higher-kinded type with the input type.
import { $ } from "hkt-toolbelt";
type Result = $<Length, [1, 2, 3]>; // 3