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> {
abstract readonly [Kind._]: unknown;
abstract f: F;
}
A HK-type is also defined via an abstract class, that extends the Kind
type.
declare abstract class Length extends Kind {
abstract f: (x: Cast<this[Kind._], unknown[]>) => typeof x["length"];
}
We encode the higher-kinded type parameter via this
. We can further use the Cast
generic to encode input constraints.
Finally, we can apply a higher-kinded type to a type via the $
generic.
export type $<F extends Kind, X extends Kind.InputOf<F>> = ReturnType<
(F & {
readonly [Kind._]: X;
})["f"]
>;
Here, we use the InputOf
type to extract and constrain the input type of the higher-kinded type. We then use the 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