Skip to content

Commit

Permalink
refactor: use conditional types to distribute over Row
Browse files Browse the repository at this point in the history
  • Loading branch information
susisu committed Jun 1, 2024
1 parent a85eb16 commit a9cc518
Showing 1 changed file with 16 additions and 12 deletions.
28 changes: 16 additions & 12 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ export type EffectData<Row extends EffectId, A> = EffectDef<A>[Row];
* `Effect<Row, A>` represents an effect that returns `A` when performed.
* It distributes over `Row` i.e. `Effect<X | Y, A> = Effect<X, A> | Effect<Y, A>`
*/
export type Effect<Row extends EffectId, A> = {
[Id in Row]: Readonly<{
id: Id;
data: EffectData<Id, A>;
}>;
}[Row];
export type Effect<Row extends EffectId, A> =
Row extends infer Id extends EffectId ?
Readonly<{
id: Row;
data: EffectData<Id, A>;
}>
: never;

/**
* `Effectful<Row, A>` represents an effectful computation that may perform effects in `Row` and
Expand Down Expand Up @@ -61,9 +62,9 @@ export function* perform<Row extends EffectId, A>(eff: Effect<Row, A>): Effectfu
* `Handler<Row, R>` handles effects in `Row` and returns a value of type `R`.
* It distributes over `Row` i.e. `Handler<X | Y, A> = Handler<X, A> | Handler<Y, A>`
*/
export type Handler<Row extends EffectId, R> = {
[Id in Row]: <A>(eff: Effect<Id, A>, resume: (value: A) => R) => R;
}[Row];
export type Handler<Row extends EffectId, R> =
Row extends infer Id extends EffectId ? <A>(eff: Effect<Id, A>, resume: (value: A) => R) => R
: never;

/**
* `Handlers<Row, R>` is a set of effect handlers.
Expand Down Expand Up @@ -94,15 +95,18 @@ export function run<Row extends EffectId, A, R>(
return ret(res.value);
} else {
const eff = res.value;
const handler = handlers[eff.id];
// eslint-disable-next-line @susisu/safe-typescript/no-type-assertion
const handler = handlers[eff.id as keyof typeof handlers];
let resumed = false;
return handler(eff, (value) => {
const resume = (value: A): R => {
if (resumed) {
throw new Error("resume cannot be called more than once");
}
resumed = true;
return loop(value);
});
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
return handler(eff as any, resume);

Check failure on line 109 in src/index.ts

View workflow job for this annotation

GitHub Actions / build (18)

Argument of type 'any' is not assignable to parameter of type 'never'.

Check failure on line 109 in src/index.ts

View workflow job for this annotation

GitHub Actions / build (20)

Argument of type 'any' is not assignable to parameter of type 'never'.
}
};
return loop();
Expand Down

0 comments on commit a9cc518

Please sign in to comment.