TGViewer
Khraks dev Khraks dev @khraks_dev · 108 subscribers
Post #51 133
# HKT Дефункционализация

В TypeScript нет настоящих Higher-Kinded Types (HKT).
А они применяются в FP - вот и ищут люди способы эмулировать.
На данный момент мне известно о двух способах
Первый называется дефункционализация и вот пример его реализации

// lib
interface URIToValue<out A> {
// Id: Container<A>
}
type URIS = keyof URIToValue<any>;
type Apply<URI extends URIS, A> = URIToValue<A>[URI];

interface Functor<URI extends URIS> {
map<A, B>(fa: Apply<URI, A>, f: (a: A) => B): Apply<URI, B>;
}

// userland Option<T>
type Option<A> = { _tag: "Some"; value: A } | { _tag: "None" };

declare module 'lib' {
interface URIToValue<out A> {
Option: Option<A>;
}
}

const optionFunctor: Functor<"Option"> = {
map(fa, f) {
//^? Option<A>
return fa._tag === "Some" ? { _tag: "Some", value: f(fa.value) } : fa;
},
};

// userland Array<T>
declare module 'lib' {
interface URIToValue<out A> {
Array: Array<A>;
}
}

const arrayFunctor: Functor<"Array"> = {
map(fa, f) {
//^? Array<A>
return fa.map(f);
},
};

Тут идея такова что мы каждый тип данных регистрируем с помощью аугментации модулей и слияния интерфейсов в реестре URIToValue и добываем настоящий тип с помощью Apply<Id, Value>

Вроде бы окей но сложности начинаются при попытке написать универсальную композицию функторов:

// Option + Array = Option<Array<T>>
// Array + Option = Array<Option<T>>

function compose<URI_outer extends URIS, URI_inner extends URIS>(
outer: Functor<URI_outer>,
inner: Functor<URI_inner>,
): Functor<URI_outer + URI_inner> {
return {
map(f_outer_inner, f) {
return outer.map(f_outer_inner, (f_inner) => inner.map(f_inner, f));

}
}
}

Чтобы сделать Apply в функции Functor.map - нам нужно ЗАРАНЕЕ зарегистрировать тип данных в реестре URIToValue - на лету не получится (`Functor<URI_outer + URI_inner>`)

И еще одна задачка появляется при композиции функторов разной арности
например хочу сделать Either + Array / Array + Either — возникнет проблема с тем как хранить и передавать E. И нужно будет добавить перегрузку compose21 (`Either<Array<A>, E>`), `compose12`(`Array<Either<A, E>>`) и т.д.

Дальше посмотрим на второй способ реализации HKT с помощью TypeLambda подхода и как этот способ решает проблемы универсальной композиции
  • 👍 2
More from @khraks_dev
  1. Sep 10, 2026Добавил еще PR с Context.Mixin, чтобы подмешивать к классу поведение Context.Service Тепер…
  2. Sep 10, 2026Post #56
  3. Sep 7, 2026Post #55
  4. Sep 3, 2026Post #54
  5. Sep 3, 2026Итак HKT на основе TypeLambda interface TypeLambda { readonly Arg1: unknown; readonly Arg2…
  6. Mar 8, 2026Combiner & Reducer В v4 добавили новые модули которые являются адаптированными Semigroup &…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →