quangv / hkt-ts

A Higher-Kinded-Types encoding for TypeScript, based on the static-land specification.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

HKT-TS

HKT-TS is an encoding for Higher-Kinded-Types (HKT) in TypeScript. It requires writing 0 overloads for your functions, and does not need to modify an existing package. This means the use of HKTs for your libraries can be opt-in, delivered by an external package, and potentially from the community!

The type-classes that are provided are primarily designed based on Static Land. Adding additional type-classes is within scope of this project, but it is a goal to avoid any specific data-structures like Maybe or Either. It'd be preferred to push those concerns out to community-based packages.

Installation

# NPM
npm i --save hkt-ts

# Yarn
yarn install hkt-ts

How to register a new HKT

import { Functor, TypeParams } from 'hkt-ts'

export const EitherUri = 'Either' // Must be a constant string
export type Left<A> = { left: true, value: A }
export type Right<A> = { left: false, value: A}
export type Either<A, B> = Left<A> | Right<B>

// The URI must match in both type-level maps to work correctly.
declare module "hkt-ts" {
  // Setup how to pass new type-parameters to a Type, looked up by the given URI.
  export interface Hkts<Params> {
    // TypeParams.First, TypeParams.Second,..., TypeParams.Fifth, are helpers for extracting
    // type parameters from Values working from right-to-left.
    [EitherUri]: Either<TypeParams.Second<Params>, TypeParams.First<Params>>
  }
  
  // Setup how to extract a Tuple of type-parameters from a registered Type, looked up by the given URI.
  export interface HktTypeParams<T> {
    // Wrapping in a tuple helps to avoid returning an invalid union e.g. [A, unknown] | [unknown, B]
    [EitherUri]: [T] extends [Either<infer A, infer B>] ? [A, B] : never
  }
}

// Create a functor instance
export const either: Functor<EitherUri> = {
  map: <A, B, C>(f: (a: A) => B, either: Either<C, A>) => Either<C, B>
}

How to create a new type-class

import { Type, TypeParams, Types } from 'hkt-ts'

// All type-classes should use an a `extends Types` clause to ensure it's working with
// registered types.
export interface Functor<T extends Types> {
  readonly map: {
    // Depending on the length of type-parameters, create the signature you'd expect or want
    1: <A, B>(f: (a: A) => B, functor: Type<T, [A]>) => Type<T, [B]>
    2: <A, B, C>(f: (a: A) => B, functor: Type<T, [C, A]>) => Type<T, [C, B]>
    3: <A, B, C, D>(f: (a: A) => B, functor: Type<T, [C, D, A]>) => Type<T, [C, D, B]>
    4: <A, B, C, D, E>(f: (a: A) => B, functor: Type<T, [C, D, E, A]>) => Type<T, [C, D, E, B]>
    5: <A, B, C, D, E, F>(
      f: (a: A) => B,
      functor: Type<T, [C, D, E, F, A]>,
    ) => Type<T, [C, D, E, F, B]>
  // Gets the number of type-params associated with a particular type T, and matches it to the appropriate signature
  }[TypeParams.Length<T>] 
}

For examples take a look within source/type-classes!

About

A Higher-Kinded-Types encoding for TypeScript, based on the static-land specification.


Languages

Language:TypeScript 99.4%Language:JavaScript 0.6%