TGViewer
Khraks dev Khraks dev @khraks_dev · 108 subscribers
Post #32 392
Хоть Effect и избавляет от проблемы раскраски функций. Все же может быть полезно отслеживать асинхронное выполнение, допустим, чтобы в решающий момент быть уверенным, что Effect.runSync не выкинет ошибку.
Для этого можно использовать такой прием - давайте помечать Effect меткой на тайп-левеле, а runSync ограничим таким образом, чтобы вызов эффекта с такой меткой был невалидным.
const AsyncTypeId: unique symbol = Symbol.for("my-project/Async");
type AsyncTypeId = typeof AsyncTypeId;

interface Async {
[AsyncTypeId]: AsyncTypeId;
}

function markAsync<A, E, R>(
effect: Effect.Effect<A, E, R>,
): Effect.Effect<A, E, R> & Async {
return effect as any;
}

function runSync<A, E, Eff extends Effect.Effect<A, E>>(
effect: Eff extends Async ? never : Eff,
) {
return Effect.runSync(effect);
}

В этом примере использовали брендирование & Async — но это наивный подход, потомучто он не будет работать с большинством встроенных функций Effect, так как они имеют сигнатуру не сохраняющую подтип самого эффекта, а оперируют только над его содержимым:
declare const map: {
<A, B>(f: (a: A) => B): <E, R>(self: Effect<A, E, R>) => Effect<B, E, R>
}

Более интересным решением будет использовать R-канал для наших целей — Effect<A, E, R | Async>. С такой сигнатурой не нужно оборачивать runSync, потомучто он требует Effect<A, E, never>. И можно ввернуть кастомный асинхронный раннер:
function runMarkedAsync<A, E, R>(effect: 
[Exclude<R, Async>] extends [never]
? Effect.Effect<A, E, R>
: Effect.Effect<A, E>
) { /* ... */ }

Мораль такова:
если нужно пометить воркфлоу каким-то образом, то стоит использовать R-канал, а не брендирование
TS-песочница с примером использования: https://tsplay.dev/m0kYaN
www.typescriptlang.org TS Playground - An online editor for exploring TypeScript and JavaScript The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
  • 👍 2
  • ✍ 1
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. Aug 30, 2026# HKT Дефункционализация В TypeScript нет настоящих Higher-Kinded Types (HKT). А они приме…
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 →