Let us consider this example, use of EventEmitter
:
import { EventEmitter } from "events";const eventEmitter = new EventEmitter();eventEmitter.on("text", text => console.log(text));eventEmitter.once("time", time => console.log(time));eventEmitter.emit("text", "hi!"); //Prints "hi!"eventEmitter.emit("time", 123); //Prints "123"eventEmitter.emit("time", 1234); //Prints nothing ( once )
In EVT the recommended approach is to give every event it's Evt
instance. Translation of the example:
import { Evt } from "evt";//Or import { Evt } from "https://evt.land/x/evt/mod.ts" on denoconst evtText = Evt.create<string>();const evtTime = Evt.create<number>();evtText.attach(text => console.log(text));evtTime.attachOnce(time => console.log(time));evtText.post("hi!");evtTime.post(123);evtTime.post(1234);
However, the traditional approach that consists of gathering all the events in a single bus is also an option.
Note: Due to a current TypeScript limitation the .attach()
methods need to be prefixed with $
when used with fλ ( to
in this case) operators but evt.$attach*()
are actually just aliases to the corresponding evt.attach*()
methods.
import { Evt, to } from "evt";const evt = Evt.create<[ "text", string ] |[ "time", number ]>();evt.$attach(to("text"), text => console.log(text));evt.$attachOnce(to("time"), time => console.log(time));evt.post(["text", "hi!"]);evt.post(["time", 123]);evt.post(["time", 1234]);
Here is a translations of the examples provided as an overview on the RxJS website.
import { fromEvent } from "rxjs";import { throttleTime, map, scan } from "rxjs/operators";fromEvent(document, "click").pipe(throttleTime(1000),map(event => event.clientX), // (TS: clientX does not exsist on type Event)scan((count, clientX) => count + clientX, 0)).subscribe(count => console.log(count));/* ------------------------------ */import { Evt, throttleTime } from "evt";Evt.from(document, "click").pipe(throttleTime(1000),event => [ event.clientX ],[(clientX, count) => [ count + clientX ], 0]).attach(count => console.log(count));
****Run the example
Unlike RxJS operators that return Observable
EVT operators are function build using native language features, no by composing other pre-existing operators or instantiating any particular class.
Consider that we have an emitter for this data type:
type Data = {type: "TEXT";text: string;} | {type: "AGE";age: number;};
We want to get a Promise<string>
that resolves with the next text event.
import { Subject } from "rxjs";import { filter, first, map } from "rxjs/operators";const subject = new Subject<Data>();const prText = subject.pipe(filter((data): data is Extract<Data, { type: "TEXT" }> =>data.type === "TEXT"),first(),map(data => data.text)).toPromise();/* ---------------------------------------------------------------- */import { Evt } from "evt";const evt = new Evt<Data>();const prText = evt.waitFor(data => data.type !== "TEXT" ?null : [data.text]);
****Run the example****
Let us consider another example involving state encapsulation. Here we want to accumulate all texts events until "STOP"
import { Subject } from "rxjs";import { map, filter, takeWhile, scan } from "rxjs/operators";const subject = new Subject<Data>();subject.pipe(filter((data): data is Extract<Data, { type: "TEXT" }> =>data.type === "TEXT"),map(data=> data.text),takeWhile(text => text !== "STOP"),scan((prev, text) => `${prev} ${text}`, "=>")).subscribe(str => console.log(str));/* ---------------------------------------------------------------- */import { Evt } from "evt";const evtData = new Evt<Data>();evtData.$attach([(data, prev) =>data.type !== "TEXT" ?null :data.text === "STOP" ?"DETACH" :[`${prev} ${data.text}`],"=>"], //<= Stateful fλ operatorstr => console.log(str));
****Run the example****
The API reference documentation is full of runnable examples that should get you started in no time.