@mizchi/domain-types
v0.0.11
Published
type utilities for domain modeling
Readme
@mizchi/domain-types
typescript utilities for domain modeling
Install
# node
$ npm add @mizchi/domain-types
# deno
$ deno add jsr:@mizchi/domain-typesEffect Generator
Thin effect-system like generator nspired by https://effect.website/ and https://koka-lang.github.io/koka/doc/index.html
simple usecase
import {
performSync,
performAsync,
defineEffect,
type EffectFor,
} from "@mizchi/domain-types";
// simple sync effect
const val = defineEffect<"val", [], number>("val");
function* program() {
yield* val();
}
const g = performSync(program(), {
[val.t]: () => 42,
});
console.log([...g]); // => [{t: "val", args: [], return: 42}]
// simple async effect
async function* asyncProgram() {
yield* val();
}
const ag = performAsync(asyncProgram(), {
[val.t]: () => 42,
});
console.log(await Array.fromAsync(ag)); // => [{t: "val", args: [], return: 42}]compose and return value
import { defineEffect, performAsync } from "@mizchi/domain-types";
const increment = defineEffect<"increment", [v: number], number>("increment");
const double = defineEffect<"double", [v: number], number>("double");
function* doubleAndAdd1(x: number) {
const v = yield* double(x);
return v + 1;
}
async function* program() {
const v = yield* increment(0);
console.assert(v === 1);
const b = yield* doubleAndAdd1(v);
console.assert(b === 3);
}
const g = performAsync(program(), {
[increment.t]: (input) => input + 1,
[double.t]: (input) => input * 2,
});
console.log(await Array.fromAsync(g));
// => [{t: "increment", args: [0], return: 1}, {t: "double", args: [1], return: 2}]real world example
import { defineEffect, performSync, performAsync } from "@mizchi/domain-types";
const get = defineEffect<"get", [path: string], string>("get");
const delay = defineEffect<"delay", [ms: number], void>("delay");
function* program() {
const data = yield* get("/data");
yield* delay(100);
return data;
}
// test for sync handlers
const g1 = performSync(program(), {
[get.t]: (path) => {
return JSON.stringify({ path, data: "mocked data" });
},
[delay.t]: (ms) => {
// nothing to do here, just simulating delay
},
});
// run as generator
[...g1];
// production
const g2 = performAsync(program(), {
[get.t]: async (path) => {
return JSON.stringify({ path, data: "mocked data" });
},
[delay.t]: async (ms) => {
await new Promise((resolve) => setTimeout(resolve, ms));
},
});
for await (const step of g2) {
console.log(step);
}type first approach
import {
defineEffect,
performAsync,
performSync,
type EffectFor,
type AsyncHandlersFor,
type SyncHandlersFor,
} from "@mizchi/domain-types";
// define effect keys
const VAL = "val" as const;
const X = "x" as const;
const Y = "y" as const;
// define effect builder
const val = defineEffect<typeof VAL, [], number>(VAL);
const x = defineEffect<typeof X, [arg1: number, arg2: number]>(X);
const y = defineEffect<typeof Y>(Y);
type ProgramEffect =
| EffectFor<typeof val>
| EffectFor<typeof x>
| EffectFor<typeof y>;
// define program as AsyncGenerator
async function* program(): AsyncGenerator<ProgramEffect> {
yield* val();
}
// define sync handlers
const syncHandlers: SyncHandlersFor<ProgramEffect> = {
[val.t]: () => 42,
[x.t]: (arg1, arg2) => {},
[y.t]: () => {},
};
// includes promise
const handlers: AsyncHandlersFor<ProgramEffect> = {
[val.t]: async () => 42,
[x.t]: async (arg1, arg2) => {},
[y.t]: () => {},
};
const g = performAsync(program(), syncHandlers);
await Array.fromAsync(g);Result
Simple result types with asserts inspired by https://github.com/supermacro/neverthrow
import {
ok,
err,
assertErr,
assertOk,
type Result,
} from "@mizchi/domain-types";
function getValue(v: number): Result<string, string> {
if (v > 0) {
return ok("Value is positive");
}
return err("Value must be positive");
}
Deno.test("Result", () => {
const result: Result<string, string> = getValue(5);
if (result.ok) {
const _: string = result.value;
} else {
const _: string = result.error;
}
});
Deno.test("Result: ok case", () => {
const result = getValue(10);
// @ts-expect-error
result.value;
assertOk(result);
console.log(result.value);
});
Deno.test("Result: err case", () => {
const result = getValue(-5);
// @ts-expect-error
result.error;
assertErr(result);
console.log(result.error);
});Error
import { assertErrorInstance } from "@mizchi/domain-types";
Deno.test("assertError", () => {
class MyError extends Error {}
const e = new MyError("test error") as any;
assertErrorInstance(e, MyError);
const _: MyError = e; // should not throw
});LICENSE
MIT
