typeCircle= { color:string; radius:number;};// Operator that ignore all non blue circle and return the radius of all blue circles.constblueRadius= (circle:Circle)=>circle.color !=="blue"?null: [circle.radius];constevtCircle=Evt.create<Circle>();// Usage with attach, ($) because it's a fλevtCircle.$attach( blueRadius, radius => { /* ... */});constradius=awaitevtCircle.waitFor(blueRadius);evtCircle.pipe(blueRadius).attach(radius=> { /* ... */ });
Operator - Filter
Let us consider the example use of an operator that filters out every word that does not start with 'H'.
It is important to be sure that your filter always return a boolean, typewise you will be warned it is not the case but you must be sure that it is actually the case at runtime.
If in doubts use 'bang bang' ( !!returnedValue ). This note also applies for Type Gard operators.
Operator - Type guard
If you use a filter that is also a type guard, the type of the callback argument will be narrowed down to the matched type.
Let us define a straight forward type hierarchy to illustrate this feature.
The matchCircle type guard can be used to attach a callback to an Evt<Shape> that will only be called against circles.
The type of the Shape object is narrowed down to Circle
If you want your operator to have side effect you should use the second argument of the operator function registerSideEffect:
This is important becaue when you can the .isHandled() method on an evt the operator is invoked. Aditionally your operator can be invoked internally by Evt, it shouldn't produce side effect.
This is why it's important to make sure the the sideEffect is executed only when there is an actuall event posted.
Generic operators
Some generic operators are provided in "evt/operators" such as scan, throttleTime or to but that's about it.
import { Evt } from "evt";
const evtText= Evt.create<string>();
evtText.attach(
text=> text.startsWith("H"),
text=> {
console.assert( text.startsWith("H") );
console.log(text);
}
);
//Nothing will be printed to the console.
evtText.post("Bonjour");
//"Hi!" will be printed to the console.
evtText.post("Hi!");
type Circle = {
type: "CIRCLE";
radius: number;
};
type Square = {
type: "SQUARE";
sideLength: number;
};
type Shape = Circle | Square;
//Type Guard for Circle:
const matchCircle = (shape: Shape): shape is Circle =>
shape.type === "CIRCLE";
import { Evt } from "evt";
const evtShape = Evt.create<Shape>();
evtShape.attach(
matchCircle,
shape => console.log(shape.radius)
);
//Nothing will be printed on the console, a Square is not a Circle.
evtShape.post({ "type": "SQUARE", "sideLength": 3 });
//"33" Will be printed to the console.
evtShape.post({ "type": "CIRCLE", "radius": 33 });
import { Evt } from "evt";
const evtShape = Evt.create<Shape>();
/*
* Filter:
* Only circle events are handled.
* AND
* to be handled circles must have a radius greater than 100
*
* Transform:
* Pass the radius of such circles to the callback.
*/
evtShape.$attach(
shape => shape.type === "CIRCLE" && shape.radius > 100 ?
[ shape.radius ] : null,
radiusOfBigCircle => console.log(`radius: ${radius}`)
//NOTE: The radius argument is inferred as being of type number!
);
//Nothing will be printed to the console, it's not a circle
evtShape.post({ "type": "SQUARE", "sideLength": 3 });
//Nothing will be printed to the console, The circle is too small.
evtShape.post({ "type": "CIRCLE", "radius": 3 });
//"radius 200" Will be printed to the console.
evtShape.post({ "type": "CIRCLE", "radius": 200 });
//Importing custom operator chunksOf that is not exported by default.
export { chunksOf } from "evt/operators/chunksOf";
export { distinct } from "evt/operators/distinct";
export { nonNullable } from "evt/operator/nonNullable";
export { onlyIfChanged } from "evt/operators/onlyIfChanged";
export { scan } from "evt/operator/scan";
export { throttleTime } from "evt/operator/throttleTime";
export { to } from "evt/operator/to";