# Why EVT ?

![](https://github.com/garronej/evt/workflows/ci/badge.svg?branch=develop) ![](https://img.shields.io/bundlephobia/minzip/evt) ![](https://img.shields.io/npm/dw/evt) ![](https://img.shields.io/npm/l/evt)

`'evt'` is intended to be a replacement for `'events'`.\
It enables and encourages **functional programming** and makes heavy use of **typescript**'s type inference features to provide **type safety** while keeping things **concise and elegant** 🍸.

**Suitable for any JS runtime env (deno, node, old browser, react-native ...)**

* ✅  It is both a [Deno](https://deno.land/x/evt) and an [NPM](https://www.npmjs.com/evt) module.&#x20;
* ✅  Lightweight, no dependency.
* ✅  No polyfills needed, the NPM module is transpiled down to ES3.
* ✅  [React Hooks integration](https://docs.evt.land/api/react-hooks)

Can be imported in TypeScript projects using version >= **3.4** (Mar 2019) and in any plain JS projects.

## Motivation

There are a lot of things that can't easily be done with `EventEmitter`:

* Enforcing **type safety**.
* Removing a particular listener ( if the callback is an anonymous function ).
* Adding a one-time listener for the next event that meets a condition.
* Waiting (via a Promise) for one thing or another to happen.

  *Example: waiting at most one second for the next message, stop waiting if the socket disconnects.*

Why would someone pick EVT over RxJS:

* RxJS introduces a lot of abstractions. It's a big jump from `EventEmitter`.
* It is often needed to resort to custom [type guards](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards), the filter operator [breaks the type inference.](https://stackblitz.com/edit/evt-795plc?embed=1\&file=index.ts\&hideExplorer=1)
* Tend to be quite verbose.
* It could be months before it eventually supports Deno.
* There is no official guideline on how to integrate it with React.

EVT is an attempt to build a lib as accessible as the `EventEmitter` yet much more powerfull.


# Overview

## `EventEmitter` comparison

Let us consider this example, use of `EventEmitter`:

```typescript
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:

```typescript
import { Evt } from "evt";
//Or import { Evt } from "https://evt.land/x/evt/mod.ts" on deno

const 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](https://github.com/microsoft/TypeScript/issues/36735) 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.

```typescript
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]);
```

[**Run the example**](https://stackblitz.com/edit/evt-honvv3?embed=1\&file=index.ts\&hideExplorer=1)

## RxJS comparison

### "Get started" examples.

Here is a translations of [the examples provided as an overview](https://rxjs-dev.firebaseapp.com/guide/overview#values) on the RxJS website.

```typescript
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**](https://stackblitz.com/edit/evt-q772em?embed=1\&file=index.ts\&hideExplorer=1)

### RxJS operators vs EVT operator

Unlike [RxJS operators](https://rxjs-dev.firebaseapp.com/guide/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:

```typescript
type Data = {
    type: "TEXT";
    text: string;
} | {
    type: "AGE";
    age: number;
};
```

We want to get a `Promise<string>` that resolves with the next text event.

```typescript
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**](https://stackblitz.com/edit/evt-795plc?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

Let us consider another example involving state encapsulation. Here we want to accumulate all texts events until `"STOP"`

```typescript
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λ operator 
    str => console.log(str)
);
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-xuutfw?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

## Where to start

The API reference documentation is full of runnable examples that should get you started in no time.


# API Documentation

The API reference documentation of the library and step-by-step guide for new users.

The [`Operator`](https://docs.ts-evt.dev/api-doc/operator) section is the place to start.


# Evt\<T>

Evt\<T> is the Class that is the equivalent of EventEmitter in "events" and Subject\<T> in "rxjs"

The method's documentation pages are ordered so that you get the more important information first.


# evt.attach\*(...)

Attach a Handler provided with a callback function to the Evt

There is multiple flavor of the attach method: `attachOnce`, `atachPrepend`, `attachExtract`... All this methods have in common to accept the same parameters and to return the same promise.

## The `$` prefix

Due to a current [TypeScript limitation](https://github.com/microsoft/TypeScript/issues/36735) the `.attach*()` methods need to be prefixed with `$` when used with fλ operators but `evt.$attach*()` are actually just aliases to the corresponding `evt.attach*()` methods.

```typescript
import { Evt } from "evt";

const evtText= new Evt<string>();


//No operator, we don't need the $ prefix
evtText.attach(text => console.log(`1: ${text}`));

//text => text.startWith("H") is a filter so we do not need the $ prefix
evtText.attach(
    text => text.startWith("H"),
    text => console.log(`2: ${text}`)
);

//text => [ text.toUpperCase() ] is a fλ operator, we need the $ prefix
evtText.$attach(
    text => [ text.toUpperCase() ],
    upperCaseText => console.log(`3: ${upperCaseText}`)
);

//Prints: 
//"1: Hello World" 
//"2: HelloWorld"
//"3: Hello World"
evtText.post("Hello World");


```

## Parameters

1. `operator:` [`Operator`](https://docs.ts-evt.dev/api-doc/operator)`<T,U>`
2. `timeout: number` Amount of time, in milliseconds before the returned promise rejects if no event has been matched within the specified delay.
3. `ctx:` [`Ctx`](https://docs.ts-evt.dev/api/ctx)A context that can be used as a reference to detach the handler later on.&#x20;
4. `callback: (data: U)=> void` Function that will be invoked every time the matcher match an event emitted by the `Evt`.

A large number of overload is provided to cover all the possible combination of arguments. The ordering in which the parameters are listed above must be respected but every parameter other than the callback can be omitted.

![](/files/-M7sqVfSMPRvTazrJY6r)

Examples:

* Only specifying a timeout: `evt.attach(timeout, callback)`
* Specifying an operator and a context: `evt.attach(op, boundTo, callback)`
* ...

## Returned Value

It no timeout argument have been passed all attach methods return `this`.

If a timeout arguement was passed a `Promise<U>` that resolves with the first event data matched by the operator. By default of operator, all the events are matched.

The returned promise can reject **only** if a timeout parameter was passed to the `attach*` method.

If no event has been matched within the specified timeout, the promise will reject with a `EvtError.Timeout.` If the event is detached before the first event is matched, the promise will reject with an `EvtError.Detached`.

If you have no use of the callback function and just want the promise, [`evt.waitFor(...)`](https://docs.ts-evt.dev/api-doc/evt#evt-waitfor) should be used in place of `evt.attach*(...)`.

## **`evt.attach(...)`**

Adds a new [handler](https://docs.ts-evt.dev/api/handler) to the end of the handlers array. No checks are made to see if the holder has already been added. Multiple calls passing the same combination of parameters will result in the `handler` being added, and called, multiple times.

## **`evt.attachOnce*(...)`**

When the method contains the keyword "**once**": Adds a **one-time** [handler](https://docs.ts-evt.dev/api/handler). The next time an event is matched this handler is detached and then it's callback is invoked.

## `evt.attach[Once]Prepend(...)`

When the method contains the keyword "**prepend**": Same as .attach() but the [`handler`](https://docs.ts-evt.dev/api/handler) is added at the *beginning* of the handler array.

```typescript
import { Evt } from "evt";

const evtLetter = Evt.create();

evtLetter
  .attach(() => console.log("B"))
  .attach(() => console.log("C"))
  .attachPrepend(() => console.log("A"))
  ;

evtLetter.post();
//"A", "B", "C" is printed to the console.
```

[**Run the example**](https://stackblitz.com/edit/evt-qshmkh?embed=1\&file=index.ts\&hideExplorer=1)

## **`evt.attach[Once]Extract(...)`**

When the method contains the "**extract**" keyword, every event that the [`handler`](https://docs.ts-evt.dev/api/handler) matches will be swallowed and no other handler will have the opportunity to handle it, even the other "extract"' handlers. It acts as a trap.

"**extract**" handler has priority even over "**prepend**" [`Handler`](https://docs.ts-evt.dev/api/handler)s.

If multiples "extractes" handlers are candidates to extract an event the handler that has been added first have priority.

```typescript
import { Evt } from "evt";

const evtCircle = new Evt<Circle>();

evtCircle.attachExtract(
    ({ radius }) => radius <= 0,
    ({ radius }) => console.log(`Circle with radius: ${radius} extracted`)
);

evtCircle.attach(
    circle => {
        //We can assume that the circle has a positive radius.
        console.assert(circle.radius > 0);
    }
);

//Extract have priority over prepend
evtCircle.attachPrepend(
    circle => console.assert(circle.radius > 0)
);
```

[**Run the example**](https://stackblitz.com/edit/evt-bwkprd?embed=1\&file=index.ts\&hideExplorer=1)


# evt.post\*(data)

## **`evt.post(data)`**

Equivalent of `eventEmitter.emit()` and `subject.next()`.

Returns evt.postCount

## **`evt.postCount: number`**

The number of times `evt.post()` has been called. It's a read-only property.

```typescript
import { Evt } from "evt";

const evtText= new Evt<string>();

//prints 0
console.log(evtText.postCount);

evtText.post("foo");
evtText.post("bar");
evtText.post("baz");

//prints 3
console.log(evtText.postCount);
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-2npimn?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

## `evt.postAsyncOnceHandled(data)`

Post the event data only once there is at least one handler candidate to handle it.

When `evt.isHandled(data)` return `true`, `post(data)` is invoked synchronously and the new post count is returned. When `postAsyncOnceHandled(data)` is invoked at a time where`evt.isHandled(data)` returns `false`, the `data` will be kept on hold and posted only once a candidate handler is attached.

`evt.post(data)` is not invoked synchronously as soon as the candidate handler is attached but is scheduled to be invoked in a microtask.\
When the call to post is delayed `postAsyncOnceHandled(data)` returns a promise that resolves with the new post count after `post(data)` has been invoked.

```typescript
import { Evt } from "evt";

function createPreloadedEvtText(): Evt<string>{

    const evtText = new Evt<string>();

    (async ()=>{

        await evtText.postAsyncOnceHandled("foo");
        evtText.post("bar");

    })();


    return evtText;

}

const evtText = createPreloadedEvtText();

evtText.attach(text => console.log("1 " + text));
evtText.attach(text => console.log("2 " + text));

console.log("BEFORE");

//"BEFORE" then (next micro task) "1 foo" "2 foo" "1 bar" "2 bar"
```

[**Run the example**](https://stackblitz.com/edit/evt-mycz4t?embed=1\&file=index.ts\&hideExplorer=1)

{% hint style="info" %}
`evt.postSyncOnceHandled()` does not exist because it is preferable to wait for the next event cycle before posting the event. For example, the previous example would not print `"2 foo"` if we had used `evt.postSyncOnceHandled()`
{% endhint %}

## `evt.postAndWait(data): Promise<void>`

Flavor of post that returns a promise that resolves after all asynchronous Handler's callbacks that matches the event data has resolved.

```typescript
import { Evt } from "evt";

const evt = Evt.create();

evt.attach(async () => {

    await new Promise(resolve => setTimeout(resolve, 100));

    console.log("bar");

});

(async () => {

    console.log("foo");

    await evt.postAndWait();

    console.log("baz");


})();

//"foo bar baz" is printed to the console.
```


# evt.waitFor(...)

Method that returns a promise that will resolve when the next matched event is posted.

waitFor is essentially evt.attachOnce(...) but you don’t provide a callback. It accepts the same arguments and return the same promise.

*Essentialy* the same but [not exactly the same](https://docs.ts-evt.dev/api/evt/evt.waitfor-...#difference-between-evt-waitfor-and-evt-attachonce), there is a key difference between a handler attached via `waitFor` and a handler attached with `attach*` as explained below.

## Without timeout

By default the promise returned by `waitFor` will never reject.

```typescript
import { Evt } from "evt";

const evtText = Evt.create<string>();

setTimeout(()=> evtText.post("Hi!"), 1500);

(async ()=>{

    //waitFor return a promise that will resolve next time 
    //post() is invoked on evtText.
    const text = await evtText.waitFor();

    console.log(text);

})();
```

[**Run the example**](https://stackblitz.com/edit/evt-cazqyr?embed=1\&file=index.ts\&hideExplorer=1)

## With timeout

As with `attach*`, it is possible to set what is the maximum amount of time we are willing to wait for the event before the promise rejects.

```typescript
import { Evt, EvtError } from "evt";

const evtText = Evt.create<string>();

(async ()=>{

    try{

        const text = await evtText.waitFor(500);

        console.log(text);

    }catch(error){

        console.assert(error instanceof EvtError.Timeout);
        //Error can be of two type:
        //  -EvtError.Timeout if the timeout delay was reached.
        //  -EvtError.Detached if the handler was detached before 
        //  the promise returned by waitFor have resolved. 

        console.log("TIMEOUT!");

    }

})();

//A random integer between 0 and 1000
const timeout= ~~(Math.random() * 1000);

//There is a fifty-fifty chance "Hi!" is printed else it will be "TIMEOUT!".
setTimeout(
    ()=> evtText.post("Hi!"), 
    timeout
);
```

[**Run the example**](https://stackblitz.com/edit/evt-wqh856?embed=1\&file=index.ts\&hideExplorer=1)

## Difference between `evt.waitFor(...)` and `evt.attachOnce(...)`

`const pr= evt.waitFor()` is **NOT** equivalent to const `pr= evt.attachOnce(()=>{})`

`evt.waitFor()` is designed in a way that makes it safe to use `async` procedures.

Basically it means that the following example prints `A B` on the console instead of waiting forever for the secondLetter.

```typescript
import { Evt } from "evt";

const evtText = Evt.create<string>();

(async ()=>{

    const firstLetter = await evtText.waitFor();
    const secondLetter = await evtText.waitFor();

    console.log(`${firstLetter} ${secondLetter}`);

})();

evtText.post("A");
evtText.post("B");

//"A B" is printed to the console.
```

Run this [**more practical example**](https://stackblitz.com/edit/evt-v4q4s2?embed=1\&file=index.ts\&hideExplorer=1) if you want to understand how this behavior prevent from some hard to figure out bugs.


# evt.evt\[Attach|Detach]

`evt.evtAttach` and `evt.evtDetach` are accessors for `Evt<Handler<T, any>>` that posts every time a new handler is attached to/detached from the `Evt<T>`.

```typescript
import { Evt } from "evt";

const evtText= new Evt<string>();

function myCallback(text: string){};

evtText.getEvtAttach().attach(
    handler=> console.log(`${handler.callback.name} attached`)
);

evtText.getEvtDetach().attach(
    handler=> console.log(`${handler.callback.name} detached`)
);

//"myCallback attached" is printed to the console.
evtText.attach(callback);

//"myCallback detached" is printed to the console.
evtText.detach();
```

[**Run the example**](https://stackblitz.com/edit/evt-xwe67h?embed=1\&file=index.ts\&hideExplorer=1)


# evt.pipe(...)

An alternative to compose for chaining operaors.

{% hint style="warning" %}
Being familiar with [`Ctx`](https://docs.evt.land/api/ctx) and [`Operator`](https://docs.evt.land/api/operator)is a prerequisite for properly using pipe.
{% endhint %}

## Return

A new Evt instance toward which are forwarded the transformed events matched by the operator(s).

## Parameters

`Ctx`: Optional, the context to which will be bound the handler responsible for forwarding events to the returned Evt.

`...Operator[]`: One or many operators composable with one another.

## Examples

There are two ways of using pipe, the first is to call pipe only once and passing it all the operators to chain, the second is to chain the `pipe` calls providing each time a single operator. Depending on the situation, you should favor one approach over the other.

Let us consider a case where the two approaches are equally valid.

Using a single call to `pipe`:

```typescript
import { Evt } from "evt";

type Circle = { type: "CIRCLE"; radius: number; };
type Square = { type: "SQUARE"; sideLength: number; };
type Shape = Circle | Square;

const evtShape = new Evt<Shape | undefined>();

evtShape.pipe(
    shape => !shape ? null : [ shape ], // Filter out undefined
    shape => shape.type !== "CIRCLE" ? null : [ shape ], // Filter Circle
    ({ radius }) => [ radius ], // Extract radius
    radius => radius > 200 ? "DETACH": [ radius ] //Detach if radius too large 
).attach(radius=> { /* ... */ });
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-jx2nnm?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

Same thing chaining `pipe`:

```typescript
const evtShape = new Evt<Shape | undefined>();

const ctx= Evt.newCtx();

evtShape
    .pipe(ctx)
    .pipe(shape => !shape ? null : [ shape ])
    .pipe(shape => shape.type !== "CIRCLE" ? null : [ shape ])
    .pipe(({ radius }) => [ radius ])
    .pipe(radius => radius > 200 ? { "DETACH": ctx } : [radius])
    .attach(radius => { /* ... */ });
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-yb4gzb?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

{% hint style="danger" %}
When chaining `pipe` if one operator in the midle of the chain returns `"DETACH"` all the handler upstream will stay attached. You must always detach the first link of the chain using a [`Ctx`](https://docs.evt.land/api/ctx).
{% endhint %}

The first approach (calling pipe only once) is preferable as it is slightly less verbose but in some cases you will reach the limits of TypeScript inference capabilities especially if you throw filters and generic operators into the mix. Bottom point is: try the first method, see how TypeScript infer the types, if detection fails fallback to chainging `pipe()`.

### Creating delegates

Pipe can also be used to create proxies to a source `Evt`.

```typescript
import { Evt } from "evt";

const evtShape = new Evt<Shape>();

//evtCircle is of type Evt<Circle> because matchCircle is a type guard.
const evtCircle = evtShape.pipe(matchCircle);

//evtLargeShape is of type Evt<Shape>
const evtLargeShape = evtShape.pipe(shape => {
  switch (shape.type) {
    case "CIRCLE":
      return shape.radius > 5;
    case "SQUARE":
      return shape.sideLength > 3;
  }
});

evtCircle.attach(({ radius }) =>
  console.log(`Got a circle, radius: ${radius}`)
);

evtLargeShape.attach(
    shape => console.log(`Got a large ${shape.type}`)
);

//"Got a circle, radius: 66" and "Got a large CIRCLE" will be printed.
evtShape.post({
  "type": "CIRCLE",
  "radius": 66
});

//Only "Got a circle, radius: 3" will be printed
evtShape.post({
  "type": "CIRCLE",
  "radius": 3
});

//Only "Got a large SQUARE" will be printed
evtShape.post({
  "type": "SQUARE",
  "sideLength": 30
});

//Nothing will be printed
evtShape.post({
  "type": "SQUARE",
  "sideLength": 1
});
```

[**Run the example**](https://stackblitz.com/edit/evt-e9zjnq?embed=1\&file=index.ts\&hideExplorer=1)


# evt.getHandlers()

List all handlers attached to the `Evt`. Returns an array of [`Handler<T,any>`](https://docs.ts-evt.dev/api/handler).

Here a use case detaching all handlers that uses a given matcher:

```typescript
import { Evt } from "evt";

const evtShape = new Evt<Shape>();

evtShape.attach(
    matchCircle,
    circle => console.log("1:", circle)
);

evtShape.attachOnce(
    matchCircle,
    circle => console.log("2:", circle)
);

evtShape.waitFor(matchCircle)
    .then(circle => console.log("3:", circle))
    ;

//Only handler that does not use matchCircle as operator.
evtShape.attach(circle => console.log("4:", circle))


evtShape.getHandlers()
    .filter(({ op }) => op === matchCircle)
    .forEach(({ detach }) => detach())
    ;

//Prints only "4: ..." other handlers are detached.
evtShape.post({ "type": "CIRCLE", "radius": 300 });
```

[**Run the example**](https://stackblitz.com/edit/evt-zufivp?embed=1\&file=index.ts\&hideExplorer=1)

### `Equivalent of EventEmitter's handler.detach(callback)`

To detach all the handlers using a given callback function as we do with `EventEmitter`:

```typescript
import { Evt } from "evt";

const evtText = new Evt<string>();

const callback = (text: string) => console.log(text);

evtText.attach(callback);

evtText.post("Foo"); //Prints "Foo"

evtText.getHandlers()
    .filter(handler => handler.callback === callback)
    .forEach(({detach})=> detach())
    ;

evtText.post("Foo"); //Prints nothing
```

[**Run the example**](https://stackblitz.com/edit/evt-wrqoct?embed=1\&file=index.ts\&hideExplorer=1)


# evt.isHandled(data)

Return true if:

* There is at least one handler matching this event data ( at least one handler's callback function will be invoked if the data is posted. )
* There is at least one handler that will be detached if the event data is posted.

```typescript
const evtText = new Evt<string>();

/*
Handle the text starting with 'h'.
Ignore all other text, when a text starting with 'g'
is posted the handler is detached
*/
evtText.$attach(
    text=> text.startsWith("h") ? 
        [ text ] : 
        text.startsWith("g") ? "DETACH" : null,
    text=> {/* do something with the text */}
);

//"true", start with 'h'
console.log(
    evtText.isHandled("hello world")
);

//"false", do not start with 'h' or 'g'
console.log(
    evtText.isHandled("foo bar")
);

//"true", not matched but will cause the handler to be detached if posted
console.log(
    evtText.isHandled("goodby world")
);
```

[**Run the example**](https://stackblitz.com/edit/evt-a3m4od?embed=1\&file=index.ts\&hideExplorer=1)


# evt.detach(ctx?)

Similar to EventEmitter.prototype.removeListener()

Detach all handlers from the Evt or all Evt's handler that are bound to a given context.

{% hint style="info" %}
The prefered way of detaching handler in TS-EVT is via [`Ctx<T>`](https://docs.ts-evt.dev/api/ctx) .
{% endhint %}

{% hint style="warning" %}
Calling this method without passing a context argument is almost never a good idea. An Evt instance should be sharable by modules that are isolated one another. If a module take the liberty to call evt.detach() it can brek the code elswhere.
{% endhint %}

{% hint style="info" %}
To chery pick the handlers to detach use [`evt.getHandlers()`](https://docs.ts-evt.dev/api/evt/evt.gethandler) or [`ctx.getHandlers()`](https://docs.ts-evt.dev/api/ctx#ctx-gethandlers)\`\`
{% endhint %}

## Returns

`Handler<T,any>[]` array of Handler that have been detached.

## Parameters

`ctx?: Ctx` If [`Ctx`](https://docs.ts-evt.dev/api/ctx) is provided only Handler bound to the given context will be removed.

## Examples

To detach all handlers at once:

```typescript
const evtText = new Evt<string>();
//detach with no argument will detach all handlers (attach, attachOnce, waitFor... )
evtText.detach();
```

Using a context argument

```typescript
import { Evt } from "evt";

const evtText = new Evt<string>();

evtText.attachOnce(text=> console.log(`Hello ${text}`));

const ctx = Evt.newCtx();

evtText.attach(
    ctx,
    _text => console.assert(false,"never")
);

evtText.attachOnce(
    ctx,
    _text => console.assert(false,"never")
);

evtText.detach(ctx);

//"Hello World" will be printed
evtText.post("World");
```

[**Run the example**](https://stackblitz.com/edit/evt-bhxla6?embed=1\&file=index.ts\&hideExplorer=1)


# evt.enableTrace(...)

If you need help to track down a bug, you can use `enableTrace` to log what's going on with an Evt.\
Use `evt.disableTrace()` to stop logging.

```typescript
import { Evt } from "evt";

{
    const evtCircle = new Evt<Circle>();

    evtCircle.enableTrace({ "id": "evtCircle n°1" });

    evtCircle.post(circle1);

    evtCircle.attachOnce(circle => {});

    evtCircle.post(circle2);

}

console.log("\n");

//Optional arguments 
{

    const evtCircle = new Evt<Circle>();

    evtCircle.enableTrace({
        "id": "evtCircle n°2",
        "formatter": circle => `CIRCLE(${circle.radius})`,
        "log": (...args)=> console.log(...["[myPrefix]",...args]) 
        // ^Log function default console log
    );

    evtCircle.attach(
        ({ radius }) => radius > 15, 
        circle => {}
    );

    evtCircle.post(circle1);
    evtCircle.post(circle2);

}
```

This will print:

```
(evtCircle n°1) 0 handler, { "type": "CIRCLE", "radius": 12 }
(evtCircle n°1) 1 handler, { "type": "CIRCLE", "radius": 33 }

[myPrefix] (evtCircle n°2) 0 handler, CIRCLE(12)
[myPrefix] (evtCircle n°2) 1 handler, CIRCLE(33)
```

[**Run the example**](https://stackblitz.com/edit/evt-vfjvfs?embed=1\&file=index.ts\&hideExplorer=1)


# evt.setMaxHandlers(n)

By default `Evt` will print a warning if more than 25 handlers are added. This is a useful default that helps finding memory leaks. Not all events should be limited to 25 handlers. The `evt.setMaxHandlers()` method allows the limit to be modified for this specific `Evt` instance. ( Use the static method [`Evt.setDefaultMaxHandlers()`](https://docs.evt.land/api/evt/setdefaultmaxhandlers) to change this limit globally.

The value can be set to `Infinity` (or 0) to indicate an unlimited number of listeners.

Returns a reference to the Evt, so that calls can be chained.


# toStateful(initialState)

See [StatefulEvt\<T>](https://docs.evt.land/api/statefulevt#converting-an-evt-into-a-statefulevt)


# evt.getStatelessOp(op)

{% hint style="warning" %}
This is an advanced feature, it you are new to EVT you can skip this for now.
{% endhint %}

It is not always possible to manually invoke an operator attached to an Handler that you got using `evt.getHandlers()`. Indeed if the operator is stateful you can't provide the `prev` value. This function gives access to this state.

Because it is such an advanced feature we just provide an example as documentation:

```typescript
//invokeOperator allow calling any type of stateless operator and 
//get a return as if the operator was a fλ
import { Evt, invokeOperator } from “evt”;


{

    const evtPoint = new Evt<number>();

    evtPoint.$attach(
        [(point, sum) => [point + sum], 0],
        sum => console.log(`sum: ${sum}`)
    );

    evtPoint.post(2); // Prints "sum: 2"

    console.log(
        invokeOperator(
            evtPoint.getStatelessOp(
                evtPoint.getHandlers()[0].op
            ),
            2
        )
    ); // Prints "[ 4 ]" ( 2 + 2 )

    evtPoint.post(3); // Prints "sum: 5" ( the state was not affected )

}

{

    const evtPoint = new Evt<number>();

    evtPoint.attach(
        point => point > 10,
        point => { } 
    );

    console.log(
        invokeOperator(
            evtPoint.getStatelessOp(
                evtPoint.getHandlers()[0].op
            ),
            5
        )
    ); // Prints "null" ( 5 < 10 )

    console.log(
        invokeOperator(
            evtPoint.getStatelessOp(
                evtPoint.getHandlers()[0].op
            ),
            15
        )
    ); // Prints "[ 15 ]" ( 15 > 10 )

}
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-yljxhq?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*


# Evt.create(initalState?)

Static method to instanciate an Evt or a StatefulEvt.

Evt.create() is the prefered method for instantiating an Evt as this single method allow to instantiate Evt, StatefulEvt and VoidEvt.

{% hint style="info" %}
The constructors are still useful however to avoid repeating the type of variable that are already typed e.g: `const evt: Evt<string | number> = new Evt()`
{% endhint %}

## Usage

```typescript
import { Evt, VoidEvt, StatefulEvt } from "evt";

Evt.create<string>()     ⇔     new Evt<string>()
Evt.create()             ⇔     /* An object that implement VoidEvt */
Evt.create(false)        ⇔     new StatefulEvt<boolean>(false)
```

## Why `VoidEvt` and not `Evt<void>` ?

When you instantiate an `Evt` with a void argument ( `new Evt<void>()` ), TypeScript forces you to pass `undefined` to the post method ( it does not allows to call `evt.post()` ).\
`VoidEvt` ( and respectively `VoidCtx` ) is a workaround for this annoyance.

`VoidEvt` object are instances of `Evt<void>` that you can post without passing argument.

```typescript
import { Evt } from "evt";

const evtSocketConnect = Evt.create();

evtSocketConnect.attach(() => console.log("SOCKET CONNECTED"));

evtSocketConnect.post();
//"SOCKET CONNECTED" have been printed on the console.
```


# Evt.newCtx\<T>()

Get a new instance of Ctx

The recommended way to get a new [`Ctx`](https://docs.ts-evt.dev/api/ctx) instance. The type argument is optional, default is void.

## Returns

* [`Ctx<T>`](https://docs.ts-evt.dev/api/ctx) if a type argument was specified
* [`VoidCtx`](https://docs.ts-evt.dev/api/ctx) if no type argument was speficied.

## Example

```typescript
import { Evt } from "evt";

const ctx = Evt.newCtx();

ctx.getPrDone().then(()=> console.log("DONE"));

ctx.done(); //Prints "DONE"

//----------------------------

const ctxData = Evt.newCtx<Uint8Array>();

ctxText.getPrDone().then(
    data=> console.log(`DONE: ${data.byteLength} bytes`)
);

ctxText.done(new Uint8Array([1,2,3])); //Prints "DONE: 3 bytes"
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-5xs5rr?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*


# Evt.getCtx(object)

A way to avoid having to create a ctx variable.

`Evt.getCtx(obj)` return an instance of `Ctx<void>`, always the same instance for a given object. Iternally it's a `WeakMap<any, Ctx>`.

No strong reference to the object is created when the object is no longer referenced it's associated Ctx will be freed from memory.


# Evt.from\<T>(...)

Creates an Evt that post events of a specific type coming from other API that emmits events.

## Returns

Evt\<T> will post every time the emitter emits

## Parameters

Ctx Optional, Allows detaching the handlers attached to the source emitter.

`emitter`: Any of the following,

* DOM EventTarget
* Node.js EventEmitter
* JQuery-like event target
* RxJS Subject
* An Array, NodeList or HTMLCollection of many of these.
* A promise

Depending of the API the type argument will be inferred or not.

`name`: The event name of interest, being emitted by the `target`.

## Example

### From `EventEmitter`

```typescript
import { Evt } from "evt";
import { EventEmitter } from "events";

const ctx= Evt.newCtx();

const ee= new EventEmitter();
const evtText= Evt.from<string>(ctx, ee, "text");
evtText.attach(text=> console.log(text));

evtText.post("Foo bar");//Prints "Foo bar";

ctx.done();

console.log(ee.listenerCount("text"));//Prints "0"
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-qyk2ny?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

### With RxJS Subject

```typescript
import { Evt } from "evt";
import { Subject } from "rxjs";

const ctx= Evt.newCtx();

const subject = new Subject<string>();

const evtText = Evt.from(ctx, subject); //The type argument is inferred.

evtText.attach(text=> console.log(text));

subject.next("Foo bar"); //Prints "Foo bar"

ctx.done();

subject.next("Foo bar"); //Prints nothing
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-t14cot?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

### With DOM EventTarget

```typescript
import { Evt } from "evt";

Evt.from(document, "click").attach(()=> console.log("Clicked!"));
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-whhtbw?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

### With JQuery-like event target

```typescript
import { Evt } from "evt";

Evt.from([
    $("#btnA"),
    $("#btnB"),
    $("#btnC")
], "click").attach(()=> console.log("Clicked!"));
```


# Evt.merge(\[ evt1, evt2, ... ])

Returns a new `Evt` instance which concurrently post all event data from every given input `Evt`.

## Return

A new `Evt` that has for type arguments the union of the type arguments of the inputs `Evt`.

## Parameters

`Ctx<any>` *Optional*, `Ctx` that will be used to detach the handler that has been attached to the input Evts.

`Evt<any>[]` Evts to be merged.

## Example

```typescript
import { Evt } from "evt";

const ctx= Evt.newCtx();

const evtText = new Evt<string>();
const evtTime = new Evt<number>();

//evtTextOrTime is Evt<string | number>, ctx is optional.
const evtTextOrTime= Evt.merge(ctx, [evtText, evtTime]);

evtTextOrTime.attach(console.log);

evtText.post("Foo bar"); //Prints "Foo bar"

ctx.done();

evtText.post("Foo bar"); //Prints nothing
```

[**Run the example**](https://stackblitz.com/edit/evt-nbshnc?embed=1\&file=index.ts\&hideExplorer=1)


# Evt.loosenType(evt)

{% hint style="info" %}
This is the identity function with special type annotations.
{% endhint %}

Swipe the type argument with a superset without giving up type safety.

If `A` is assignable to `B` ⇒ `Evt<A>` is assignable to `Evt<B>`

e.g:`Evt<1|2|3>` is assignable to `Evt<number>` however typescript wont let you do this assignation. This is where `Evt.loosenType` come in handy.

```typescript
import { Evt } from "evt";

declare const evFooBar: Evt<"FOO" | "BAR">; 
declare function myFunc(evtText: Evt<string>): void;

myFunc(evtFooBar); //Gives a type error; 
myFunc(Evt.loosenType(evtFooBar)); //OK
```


# Evt.factorize(evt)

{% hint style="info" %}
This is the identity function with special type annotations.
{% endhint %}

If you have a variable that is either an `Evt` that post `A` or an `Evt` that post `B` you have an event that post `A or B`.

In other words `Evt<A> | Evt<B>` is assignable to `Evt<A | B >.` This method implement this proerty.

```typescript
import { Evt, VoidEvt, matchVoid } from "evt";

declare evt: Evt<string> | Evt<number> | VoidEvt = Evt.create<any>();

evt.attach(data=> { }); // TS ERROR

Evt.factorize(evt) // OK, return Evt<string | number | void>
    .attach(data=> { // data is string | number | void

        //To test if data is void
        if( matchVoid(data) ){
            return;
        }

        //Here data is string | number.

    })
    ;
```

See also [`FactorizeEvt<E>`](https://docs.evt.land/api/helpertypes#swapevttype-less-than-e-t-greater-than), helper type that this method levrage.


# Evt.asPostable(evt)

Cast the passed event as portable.

{% hint style="info" %}
Evt.asNonPostable() is the identity function with special type annotation
{% endhint %}

{% hint style="warning" %}
Use this method only on`Evt` you instantiated yourself. Not as a hack to trigger events on `Evt` that have been exposed as non-postable by an API.
{% endhint %}

To invoke `post()` on a `NonPostableEvt` or a `StatefullReadonlyEvt`.

## Usecase:

Without this method this would be the way for a class to expose `Evt` that are posted internally and exposed to be listened.

```typescript
import { Evt } from "evt";

class Socket2 {

    private readonly _evtIsConnected= Evt.create(false);
    private readonly _evtMessage= Evt.create<Uint8Array>();

    readonly evtIsConnected= Evt.asNonPostable(this._evtIsConnected);
    readonly evtMessage= Evt.asNonPostable(this._evtMessage);

    /* 
        OR, more explicit but require to repeat the types and to
        import type { StatefulReadonlyEvt, NonPostableEvt } from "evt";

    readonly evtIsConnected: StatefulReadonlyEvt<boolean>= this._evtIsConnected;
    readonly evtMessage: NonPostableEvt<Uint8Array> = this._evtMessage;
    */

    constructor(){

        this._evtIsConnected.state = true;
        this._evtMessage.post(new Uint8Array(111));

    }

}
```

Now it can be frustrating to have to store a private property only to call post on a object that we know is postable. Here is were this method come in handy:

```typescript
class Socket {

    readonly evtIsConnected= Evt.asNonPostable(Evt.create(false));
    readonly evtMessage= Evt.asNonPostable(Evt.create<Uint8Array>());

    constructor(){

        Evt.asPostable(this.evtIsConnected).state = true;
        Evt.asPostable(this.evtMessage).post(new Uint8Array(111));

    }


}
```


# Evt.asNonPostable(evt)

{% hint style="info" %}
Evt.asNonPostable() is the identity function with special type annotation
{% endhint %}

Return the passed evt typed as an object that can't be posted.

## Usecase:

Take [this example](https://docs.evt.land/api/statefulevt#make-a-statefulevt-readonly).

You could use this function to enforce that the return type by inferred and save you the trouble of having to import the `StatefulReadonlyEvt` interface:

```typescript
import { Evt } from "evt";

//Return an event that post every second.
function generateEvtTick(delay: number) {

    const evtTick= Evt.create(0);

    setInterval(()=> evtTick.state++, delay);

    retrun Evt.asNonPostable(evtTick);

}

const evtTick= generateTick(1000);


evtTick.state++; // TS ERROR
evtTick.post(2); // TS ERROR
```


# Evt.setDefaultMaxHandlers(n)

By default if an `Evt` is attached more than 25 handlers a warning will be displayed. It is possible to increase this limmit on a specific `Evt` instance using [`evt.setMaxHandlers(n)`](https://docs.evt.land/api/evt/setmaxhandlers) or globally with this static method.

Using this method will not overwrite the vale set on specific instance with `evt.setMaxHandlers(n)`.

Use Infinity or 0 to completely disable the warning.

{% hint style="warning" %}
Different version of EVT can be coabitating in a single project. The modification will only apply to the `Evt`s instantiated by this constructor.
{% endhint %}


# Ctx\<T>

`Ctx` helps detach all `Handler`s that were attached in the goal of acompishing a certain task once the said task is done or aborted.

{% hint style="info" %}
Get Ctx instance using[`Evt.newCtx<T>()`](https://docs.evt.land/api/evt/newctx) or [`Evt.getCtx(obj)`](https://docs.evt.land/api/evt/getctx)
{% endhint %}

{% hint style="info" %}
The only difference between `CtxVoid` and `Ctx<void>` is that `ctxVoid.done()` can be called without argument when `ctx<void>.done(result)`must be called with an argument (`null` or `undefined`).
{% endhint %}

## `ctx.done(result?)`

Detach, from the `Evt` instances they are attached to, all Handlers bound to the context.

Calling this method causes the `Evt` returned by `ctx.getEvtDone()` to be posted.

{% hint style="info" %}
When an fλ operator return `{ "DETACH": ctx }`, `ctx.done()` is invoked.

When it returns `{ "DETACH": ctx, "res": result }`, `ctx.done(result)` is invoked.
{% endhint %}

{% hint style="info" %}
To test if ctx.done() have been invoked already you can use:`ctx.getEvtDone().postCount !== 0`
{% endhint %}

### Returns

`ReturnType<ctx.getHandlers()>` All the [Handler](https://docs.ts-evt.dev/api/handler)s that were bound to the context. They are now detached, calling `ctx.getHandler()` just after `ctx.done()` returns an empty array.

### Parameter

* `T` for `Ctx<T>`
* none for `VoidCtx`

## `ctx.abort(error)`

Equivalent of `ctx.done()` to use when the task did not go through.

{% hint style="info" %}
When a fλ operator returns `{ "DETACH": ctx, "err": error }`, `ctx.abort(error)` is invoked.
{% endhint %}

### Returns

`ReturnType<ctx.done()>` (cf `ctx.done` )

### Parameter

`Error` an error that describes what went wrong.

## `ctx.evtDoneOrAborted`

Tracks when ctx.done or ctx.abort are invoked.

{% hint style="info" %}
For most use cases, it is more convenient to use `ctx.waitFor([timeout])`
{% endhint %}

### Returns

* For VoidCtx an Evt that posts:
  * `{ handlers: Handler.WithEvt[] }` when `ctx.done()` is called.
  * `{ error: Error, handlers: Handler.WithEvt[] }` when `ctx.abort(error)` is called.
* For `Ctx<T>`, an `Evt` that post:
  * `{ result: Result; handlers: Handler.WithEvt[]; }` when `ctx.done(result)` is called.
  * `{ error: Error, handlers: Handlers.WithEvt[]; }` when `ctx.abort(error)` is called.

`Handler.WithEvt<T>` is just a type alias for an object that wraps a handler and the `Evt` it is attached to: `{ handler: Handler<T, any>, evt: Evt<T> }`

### Example

```typescript
import { Evt } from "evt";
import { EventEmitter } from "events";

const ctx= Evt.newCtx();

const evtText = new Evt<string>();
const evtTime = new Evt<number>();

evtText.$attach(
    text=> [ text.length ],
    ctx, 
    count => console.log("1: " + count)
);

evtTime.waitFor(
    time => time < 0,
    ctx,
).then(time=> console.log("2: " +  time));

evtText
    .pipe(ctx)
    .pipe(text => [text.toUpperCase()])
    .attach(upperCaseText=> console.log("3: " + upperCaseText))
    ;

Evt.merge(ctx, [ evtText, evtTime ])
    .attach(textOrTime => console.log("4: " + textOrTime))
    ;

const ee= new EventEmitter();

Evt.from<string>(ctx, ee, "text")
    .attach(text=> console.log("5: " + text))
    ;


evtText.post("foo"); //Prints "1: 3" "3: FOO" "4: foo"
ee.emit("text", "bar"); //Prints "5: bar"

console.log(evtText.getHandlers().length); //Prints "3"
console.log(evtTime.getHandlers().length); //Prints "2"

console.log(ee.listenerCount("text")); //Print "1"

ctx.evtDoneOrAborted.attachOnce(
    ({handlers})=> {

        console.log(
            handlers.filter(({ evt })=> evt === evtText).length +
            " handlers detached from evtText"
        );

        console.log(
            handlers.filter(({ evt })=> evt === evtTime).length +
            " handlers detached from evtTime"
        );

        console.log(
            handlers.length + " handlers detached total"
        );

    }
);

//Prints:
//"3 handlers detached from evtText"
//"2 handlers detached from evtTime"
//"5 handlers detached total"
ctx.done();

console.log(evtText.getHandlers().length); //Prints "0"
console.log(evtTime.getHandlers().length); //Prints "0"
console.log(ee.listenerCount("text")); //Print "0"

evtText.post("foo"); //Prints nothing
ee.emit("text", "bar"); //Prints nothing
```

[**Run the example**](https://stackblitz.com/edit/evt-niwafz?embed=1\&file=index.ts\&hideExplorer=1)

## `ctx.waitFor([timeout])`

Tracks via a Promise that resolves when `ctx.done()` or `ctx.abort()` is invoked.

### Returns

`Promise<T>` (`T` is the type argument of `Ctx<T>` ) A promise that resolve when ctx.done(\[result]) is invoked.

If `ctx.abort(error)` is invoked before `ctx.done()` the promise rejects with `error`.

If timeout was specified the promise rejects if `ctx.done()` was not invoked within `timeout` milliseconds. If it happens `ctx.abort(timeoutError)` is internally invoked `timeoutError` being an instance of `EvtError.Timeout`.

### Parameter

`number` Optional, number of milliseconds before the promise reject if it hasn't fulfilled within this delay.

## `ctx.getHandlers()`

### Returns

`Handler.WithEvt[]` The [`Handler`](https://docs.ts-evt.dev/api/handler)s that are bound to the context alongside with the `Evt` instance each one is attached to. The Handlers that are bound to the context but no longer attached to an Evt are not listed ( they are usually freed from memory anyway as there should be nor reference left of them as soon as they are detached ).

### Example

```typescript
//NOTE: Equivalent to evt.detach(ctx);
ctx
    .getHandlers()
    .filter(({ evt }))=> evt === evtString)
    .forEach(({ handler })=> handler.detach())
    ;
```

## `ctx.evtAttach`

### Returns

`Evt<Handler.WithEvt<any>>` An Evt that posts every time a new handler bound to the context is attached.

```typescript
import { Evt } from "evt";

const evtText = new Evt<string>();

const ctx= Evt.newCtx();

ctx.evtAttach.attach(handler => console.log(handler.timeout));

const timeout = 43;

evtText.attach(timeout, ()=>{}); //Prints "43"
```

[**Run the example**](https://stackblitz.com/edit/evt-t17qsy?embed=1\&file=index.ts\&hideExplorer=1)

## `ctx.evtDetach`

Same as `ctx.getEvtAttach()` but post when handlers are detached. Note that a handler being detached does not mean that it has been explicitly detached. One-time handlers and handlers that have timed out are automatically detached.

## Comprehensive example

Let us consider a practical use case of `Ctx`. The task is to download a file, we know the size of the file to download, we have an `Evt<Uint8Array>` that emits chunks of data, we want to accumulate them until we reach the expected file size. Multiple things can go wrong during the download:

* The user can cancel the download.
* The download can take too long.
* Socket may disconnect .
* The socket may send more data than expected.

Our expected output is a `Promise<Uint8Array>` that resolves with the downloaded file or reject if anything went wrong.

This is a possible implementation using `Ctx<Uint8Array>`:

```typescript
import { Evt, VoidEvt } from "evt";

function downloadFile(
    { fileSize, evtChunk, evtBtnCancelClick, evtSocketError, timeout }: {
        fileSize: number;
        evtChunk: Evt<Uint8Array>;
        evtBtnCancelClick: VoidEvt;
        evtSocketError: Evt<Error>;
        timeout: number;
    }
): Promise<Uint8Array> {

    const ctxDl = Evt.newCtx<Uint8Array>();

    evtSocketError.attachOnce(
        ctxDl,
        error => ctxDl.abort(error)
    );

    evtBtnCancelClick.attachOnce(
        ctxDl,
        () => ctxDl.abort(new Error("Download canceled"))
    );

    evtChunk
        .pipe(ctxDl)
        .pipe([
            (chunk, { byteLength, chunks }) => [{
                "byteLength": byteLength + chunk.length,
                "chunks": [...chunks, chunk]
            }],
            {
                "byteLength": 0,
                "chunks": id<Uint8Array[]>([])
            }
        ])
        .pipe(({ byteLength }) => byteLength >= fileSize)
        .pipe(({ byteLength, chunks }) => byteLength !== fileSize ?
            { "DETACH": ctxDl, "err": new Error("File is larger than expected") } :
            [chunks]
        )
        .pipe(chunks => [concatTypedArray(chunks, fileSize)])
        .attach(rawFile => ctxDl.done(rawFile))
        ;

    return ctxDl.waitFor(timeout);

}
```

[**Run the example**](https://stackblitz.com/edit/evt-qpke6h?embed=1\&file=index.ts\&hideExplorer=1)

Whether the download is successful or not this use of `Ctx` enforce that there is no left over handlers on the `Evt` passed as input once the download attempt has completed.


# Operator\<T, U> (type)

Operators provide a way to transform events data before they are passed to the callback.

EVT Operators can be of three types:

* **Filter**: `(data: T)=> boolean`.

  Only the matched event data will be passed to the callback.
* **Type guard**: `<U extends T>(data: T)=> data is U`

  Functionally equivalent to filter but restrict the event data type.
* **fλ**

  Filter / transform / detach handlers

  * **Stateless fλ**: `<U>(data: T)=> [U] | null | "DETACH" | {DETACH:`[`Ctx`](https://docs.ts-evt.dev/api/ctx)`} |...` &#x20;
  * **Stateful fλ**: `[ <U>(data: T, prev: U)=> ..., U ]`

    Uses the previous matched event data transformation as input à la `Array.prototype.reduce`

{% hint style="warning" %}
Operators do not have to be [pure](https://en.wikipedia.org/wiki/Pure_function), they can use variables available in scope and involve time `(Date.now())`, but they **must not have any side effect**. In particular they cannot modify their input.
{% endhint %}

## Operator - Filter

Let us consider the example use of an operator that filters out every word that does not start with 'H'.

```typescript
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!");
```

[**Run the example**](https://stackblitz.com/edit/evt-38z5nd?embed=1\&file=index.ts\&hideExplorer=1)

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](https://docs.evt.land/api/operator#operator-type-guard).

## Operator - Type guard

If you use a filter that is also a [type guard](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards), 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.

```typescript
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";
```

The `matchCircle` type guard can be used to attach a callback to an `Evt<Shape>` that will only be called against circles.

```typescript
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 });
```

The type of the Shape object is narrowed down to `Circle`\
![Screenshot 2020-02-08 at 19 17 46](https://user-images.githubusercontent.com/6702424/74090059-baab3e00-4aa7-11ea-9c75-97f1fb99666d.png)

[**Run the example**](https://stackblitz.com/edit/evt-nn29kf?embed=1\&file=index.ts\&hideExplorer=1)

## Operator - fλ

Anonymous functions to simultaneously filter, transform the data and control the event flow.

**fλ Returns**

The type of values that a fλ operator sole determine what it does:

* `null` If the event should be ignored and nothing passed to the callback.
* `[ U ]` or `[ U, null ]` When the event should be handled, wrapped into the singleton is the value will be passed to the callback.
* `"DETACH"` If the event should be ignored and the handler detached from the `Evt`
* `{ DETACH: Ctx<void> }` If the event should be ignored and a group of handlers bound to a certain context be detached. See [`Ctx<T>`](https://docs.ts-evt.dev/api/ctx)
* `{ DETACH: Ctx<V>, res: V }`  See [`Ctx<T>`](https://docs.ts-evt.dev/api/ctx)\`\`
* `{ DETACH: Ctx; err: Error }`  See [`Ctx<T>`](https://docs.ts-evt.dev/api/ctx)\`\`
* `[ U, "DETACH" ]` / `[ U, {DETACH:Ctx, ...} ]` If the event should be handled AND some detach be performed.

### **Stateless fλ**

Stateless fλ operator only takes the event data as arguments.

```typescript
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 });
```

Other example using `"DETACH"`

```typescript
import { Evt } from "evt";

const evtText= Evt.create<"TICK" | "END">();

/*
 * Only handle events that are not "END".
 * If the event is "END", detach the handler.
 * Pass the event data string in lower case to the callback.
 */
evtText.$attach(
    text => text !== "END" ? [ text.toLowerCase() ] : "DETACH",
    text => console.log(text) 
);

evtText.post("TICK"); //"tick" is printed to the console
evtText.post("END"); //Nothing is printed on the console, the handler is detached
evtText.post("TICK"); //Nothing is printed to the console.
```

Example use of `[U,null|"DETACH"]`, handling the event that causes the handler to be detached.

```typescript
const evtText= Evt.create<"TICK" | "END">();

evtText.$attach(
    text => [ text, text === "END" ? "DETACH" : null ],
    text => console.log(text) 
);

evtText.post("TICK"); //"TICK" is printed to the console
evtText.post("END"); //"END" is printed on the console, the handler is detached.
evtText.post("TICK"); //Nothing is printed to the console the handler has been detached.
```

Example use of `{ DETACH:`[`Ctx`](https://docs.ts-evt.dev/api-doc/ctx)`}`, detaching a group of handlers bound to a given context.

```typescript
const evtBtnClick = Evt.create<"OK" | "QUIT">();

const evtMessage = Evt.create<string>();
const evtNotification = Evt.create<string>();

const ctx= Evt.newCtx();

evtMessage.attach(
    ctx,
    message => console.log(`message: ${message}`)
);

evtNotification.attach(
    ctx,
    notification => console.log(`notification: ${notification}`)
);

evtBtnClick.$attach(
    type => [ 
        type, 
        type !== "QUIT" ? null : { "DETACH": ctx } 
    ],
    type => console.log(`Button clicked: ${type}`)
);

evtBtnClick.post("OK"); //Prints "Button clicked: OK"
evtMessage.post("Hello World"); //Prints "Message: Hello World"
evtNotification.post("Poke"); //Prints "Notification: Poke"
evtBtnClick.post("QUIT"); //Prints "Button clicked: QUIT", handlers are detached...
evtMessage.post("Hello World 2"); //Prints nothing
evtNotification.post("Poke 2"); //Prints nothing
evtBtnClick.post("OK"); //Prints "Button clicked: OK", evtBtnClick handler hasn't been detached as it was not bound to ctx.
```

[**Run examples**](https://stackblitz.com/edit/evt-mf3nzt?embed=1\&file=index.ts\&hideExplorer=1)

### **Stateful fλ**

The result of the previously matched event is passed as argument to the operator.

```typescript
import { Evt } from "evt";

const evtText= Evt.create<string>();

evtText.$attach(
    [ 
        (str, prev)=> [`${prev} ${str}`], 
        "START: "  //<= seed
    ],
    sentence => console.log(sentence)
);

evtText.post("Hello"); //Prints "START: Hello"
evtText.post("World"); //Prints "START: Hello World"
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/ts-evt-demo-stateful-qs1nsh?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

### Dos and don'ts

Operators cannot have any side effect (they cannot modify anything). No assumption should be made on when and how they are called.

#### Don't encapsulate state, do use stateful **fλ**

The first thing that you might be tempted to do is to use a variable available in the operator's scope as an accumulator.

The following example **seems equivalent from the previous one** but it is **not**.

```typescript
const evtText= Evt.create<string>();

//🚨 DO NOT do that 🚨...
evtText.$attach(
    (()=> {

        let acc= "START:";

        return (data: string) => [acc += ` ${data}`] as const;

    })(),
    sentence => console.log(sentence)
);

const text= "Foo bar";

if( evtText.isHandled(text) ){
    //Prints "START: Foo Bar Foo bar", probably not what you wanted...
    evtText.post(text); 
}
```

When evt.isHandled(data) is invoked the operator of every handler is invoked. The operator is invoked again when the event is actually posted.

In the example every time the operator is invoked the encapsulated variable acc is updated. This result in "Foo bar" being accumulated twice when the event is posted only once.

`evt.postAsyncOnceHandled(data)` will also cause dry invokations of the operators.

If state is needed stat full fλ have to be used.

#### Don't modify input, do return a copy.

```typescript
import { Evt } from "evt";

const evtText= Evt.create<string>();

//Do not modify the accumulator value.
evtText.$attach(
    [
        (text, arr: string[])=> {
            arr.push(text);
            return [arr];
        },
        []
    ],
    arr=> { /*...*/ }
);

/* ----------------------------- */

//Do Return a new array
evtText.$attach(
    [
        (text, arr: string[]) => [[...arr, text]],
        []
    ],
    arr=> { /*...*/ }
);
```

#### Do use const assertions ( `as const` )

The TypeScript [const assertion features](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions) come in handy if you introduce closures, for example. The following example does not compile without the use of `as const`.

```typescript
const evtShapeOrUndefined = Evt.create<Shape | undefined>();

evtShapeOrUndefined.$attach(
    shape => !shape ?
        null :
        (() => {
            switch (shape.type) {
                case "CIRCLE": return [shape.radius] as const;
                case "SQUARE": return [shape.sideLength] as const;
            }
        })(),
    radiusOrSide => { /* ... */ }
);
```

Generally const assertions can help you narrow down the return type of your operator. In the following example without the const assertions `data` is inferred as being `string | number` , with the const assertions it is `"TOO LARGE" | number`

```typescript
import { Evt } from "evt";

const evtN = Evt.create<number>();

evtN.$attach(
    n => [ n>43 ? "TOO LARGE" as const : n ], 
    data=> { /* ... */ }
);
```

#### Do write single instruction function, try to avoid explicit return.

This is more a guideline than a requirement but you should favor `data => expression` over `data=> { ...return x; }` wherever possible for multiple reasons:

1. It is much less likely to inadvertently produce a side effect writing a single expression function than it is writing a function with explicit returns.
2. Operators are meant to be easily readable. If you think the operator you need is too complex to be clearly expressed by a single instruction, you should consider splitting it in multiple operators and using the compose function introduced in the next section.
3. It is easier for TypeScript to infer the return type of single expression functions.

Here is the previous example using explicit returns just to show you that the return type has to be explicitly specified, this code does not copy without it.

```typescript
import { Evt } from "evt";

const evtN = Evt.create<number>();

//🚨 This is NOT recomanded 🚨...
evtN.$attach(
    (n): [ "TOO LARGE" | number ] => {
        if( n > 43 ){
            return [ "TOO LARGE" ];
        }
        return [n];
    }, 
    data=> { /* ... */ }
);.
```

## `compose(op1, op2, ..., opn)`

$$
op\_n \circ... \circ op\_2 \circ op\_1
$$

Operators can be composed ( aka piped ) to achieve more complex behaviour.

{% hint style="info" %}
For most use cases, it is more convenient to chain [`evt.pipe()`](https://docs.evt.land/api/evt/pipe) calls rather than using compose. However it is very useful for creating custom operators.
{% endhint %}

Example composing type guards with fλ:

```typescript
import { Evt, compose } from "evt";

const evtShape= Evt.create<Shape>();

evtShape.$attach(
    compose(
        matchCircle,
        ({ radius })=> [ radius ]
    ),
    radius => console.log(radius)
);

//Prints nothing, Square does not matchCircle
evtShape.post({ "type": "SQUARE", "sideLength": 10 }); 
//Prints "12"
evtShape.post({ "type": "CIRCLE", "radius": 12 });
```

Example with [`on`](https://docs.evt.land/overview#eventemitter-comparison) ( operator used to do things à la `EventEmitter`)

```typescript
import { Evt, to, compose } from "evt";

const evt = Evt.create<
    ["text", string] |
    ["time", number]
>();

evt.$attach(
    compose(
        to("text"), 
        text => [ text.toUpperCase() ]
    )
    text => console.log(text)
);

evt.post(["text", "hi!"]); //Prints "HI!" ( uppercase )
```

Example composing three fλ to count the number of different words in a sentence:

```typescript
import { Evt, compose } from "evt";

const evtSentence = Evt.create<string>();

evtSentence.$attach(
    compose(
        str=> [ str.toLowerCase().split(" ") ],
        arr=> [ new Set(arr) ],
        set=> [ set.size ]
    ),
    numberOfUniqWordInSentence => console.log(numberOfUniqWordInSentence)
);

evtSentence.post("Hello World"); //Prints "2"
evtSentence.post("Boys will be boys"); //Prints "3", "boys" appears twice.
```

Using stateful fλ operators to implement `throttleTime(duration)`, an operator that let through at most one event every `duration` milliseconds.

```typescript
import { Evt, compose } from "evt";

const throttleTime = <T>(duration: number) =>
    compose<T, { data: T; lastClick: number; }, T>(
        [
            (data, { lastClick }) => 
                 Date.now() - lastClick < duration ?
                    null :
                    [{ data, "lastClick": Date.now() }],
            { "lastClick": 0, "data": null as any }
        ],
        ({ data }) => [data]
    )
    ;

const evtText = Evt.create<string>();

evtText.$attach(
    throttleTime(1000), //<= At most one event per second is handled.
    text => console.log(text)
);

setTimeout(()=>evtText.post("A"), 0); //Prints "A"
//Prints nothing, the previous event was handled less than 1 second ago.
setTimeout(()=>evtText.post("B"), 500);
//Prints nothing, the previous event was handled less than 1 second ago.
setTimeout(()=>evtText.post("B"), 750); 
setTimeout(()=>evtText.post("C"), 1001); //Prints "C"
setTimeout(()=>evtText.post("D"), 2500); //Prints "D"
```

[**Run the example**](https://stackblitz.com/edit/evt-dkx3kn?embed=1\&file=index.ts\&hideExplorer=1)

{% hint style="warning" %}
Unless all the operators passed as arguments are stateless the operator returned by `compose` is **not** reusable.
{% endhint %}

```typescript
import { Evt, compose } from "evt";

//Never do that: 
{

const op= compose<string,string, number>(
    [(str, acc)=>[`${acc} ${str}`], ""],
    str=> [str.length]
);

const evtText= Evt.create<string>();

evtText.$attach(op, n=> console.log(n));
evtText.$attach(op, n=> console.log(n));

evtText.post("Hello World"); //Prints "12 24" ❌

}

console.log("");

//Do that instead: 
{

const getOp= ()=> compose<string,string, number>(
    [(str, acc)=>[`${acc} ${str}`], ""],
    str=> [str.length]
);

const evtText= Evt.create<string>();

evtText.$attach(getOp(), n=> console.log(n));
evtText.$attach(getOp(), n=> console.log(n));

evtText.post("Hello World"); //Prints "12 12" ✅

}
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-gmzzzx?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

## Explicitly using the type alias

The `Operator` type alias defines what functions qualify as a valid EVT operaor. The type can be used as a scaffolder to write fλ.

In `Operator<T, U>` , `T` design the type of the event data and `U` design the type of the data spitted out by the operator. For filters operator `U=T`.

```typescript
import type { Operator } from "evt";

//A function that take an EVT operator as argument.
declare function f<T, U>(op: Operator<T, U>): void;

//Les's say you know you want to create an operator that take string
//and spit out number you can use the type alias as scaffolding.
const myStatelessFλOp: Operator.fλ<string, number> =
    str => str.startsWith("H")? null : [ str.length ];
//The shape argument is inferred as being a string and TS control that you
//are returning a number (str.length) as you should.

f(myStatelessFλOp); //OK, f<Shape,number> Operator.fλ is assignable to Operator.

//An other example creating an stateful operator
const myStatefulFλOp: Operator.fλ<string, number> =
    [
        (data, prev) => [prev + data.length],
        0
    ];

f(myStatefulFλOp); //OK, f<string, number>

//Filter and TypeGuard don't need scaffolding but they are valid Operator

f((data: string) => data.startsWith("H")); // OK, TS infer f<string, string>
f((n: number): n is 0 | 1 => n === 0 || n === 1); // OK, TS infer f<number, 0 | 1>
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-agatnh?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

## Generic operators built in

{% hint style="warning" %}
Generic operators such as `bufferTime` `debounceTime`, `skip`, `take`, `switchMap`, `mergeMap` and `reduce`Will be added later on alongside creators. To implement those we need a third type of operator called `AutonomousOperators` that will ship in the next major release.
{% endhint %}

Some generic operators are provided in `"evt/lib/util/genericOperators"` such as `scan`, `throttleTime` or `to` but that's about it.

```typescript
//Importing custom operator chunksOf that is not exported by default.
import { chuncksOf } from "evt/lib/util/genericOperators";
```

## Where to use operators

Operators functions can be used with:

* All the [`evt.attach*(...)`](https://docs.ts-evt.dev/api-doc/evt#evt-usd-attach-methods) methods. [They have to be prefixed with `$` when used with fλ](https://docs.ts-evt.dev/api/evt/evt.-usd-attach-...-methods#the-usd-prefix).
* The [`evt.waitFor(...)`](https://docs.ts-evt.dev/api-doc/evt#evt-waitfor)   method
* The [`evt.pipe(...)`](https://docs.ts-evt.dev/api-doc/evt#evt-pipe) method.


# StatefulEvt\<T>

A `StatefulEvt` is an Evt stat keep a reference to the last value posted.

You can think of it as way to observe when a value is changed.

## `.state`

Property type: `T`

reading the property gives the last event data posted. Setting the property (`evt.state = data`) is equivalent to calling `.post(data)`.

{% hint style="danger" %}
In v2 `evt.state = data` will only trigger the call of `.post(data)` if `data !== evt.state`

Consult v2 roadmap [here](https://github.com/garronej/evt/pull/16)
{% endhint %}

```typescript
import { Evt } from "evt";

const evtCount = Evt.create(0); // Equivalent wit new StatefulEvt<number>(0)

evtCount.attach(console.log);

console.log(evtCount.state); //Pints "state: 0"

evtIsConnected.post(1); //Pints "1" 

console.log(evtCount.state); //Prints "1";

evtCount.state++; //Prints "2"

console.log(evtCount.state); //Pints "2";
```

## `.evtChange`

Property type: `ReadonlyStatefulEvt<T>`

The `.evtChange` property is an `Evt` that post only when the `.state` has changed. ( or when post is made via `.postForceChange()` )

```typescript
import { Evt } from "evt";

const evtIsConnected = Evt.create(false);

evtIsConnected.attach(console.log);

evtIsConnected.state = false; //Prints nothing .state was already false.
evtIsConnected.state = true; //Prints "true";
```

## `.evtDiff`

Property type: `NonPostableEvt<{prevState:T; newState: T}>`

Posted every time the Evt is posted. Used to compare the previous state with the new state.

```typescript
import { Evt } from "evt";

const evtColor = Evt.create<"BLUE"|"RED"|"WHITE">("BLUE");
evtColor.evtDiff.attach(
    ({ prevState, newState})=> console.log(`${prevState}=>${newState}`)
);

evtColor.state= "BLUE"; //Prints "BLUE=>BLUE"
evtColor.state= "WHITE"; //Prints "BLUE=>WHITE"
```

## `.evtChangeDiff`

Property type: `NonPostableEvt<{prevState:T; newState: T}>`

Same than .evtDiff but post only when .evtChang post.

```typescript
import { Evt } from "evt";

const evtColor = Evt.create<"BLUE"|"RED"|"WHITE">("BLUE");
evtColor.evtChangeDiff.attach(
    ({ prevState, newState})=> console.log(`${prevState}=>${newState}`)
);

evtColor.state= "BLUE"; //Prints nothing
evtColor.state= "WHITE"; //Prints "BLUE=>WHITE"
```

## `.pipe(...)`

Same as [`evt.pipe(...)`](https://docs.evt.land/api/evt/pipe) but return a `StatefulEvt`. Be aware that the current state of the `StatefulEvt` must be matched by the operator ( if any ) when invoking `.pipe()`, elst an exception will be thrown.

```typescript
import { Evt } from "evt";

type Circle = { 
    color: "WHITE" | "RED";
    radius: number;
};

const evtSelectedCircle = Evt.create<Circle>({ "color": "RED", "radius": 3 });

const evtSelectedCricleColor = 
    evtSelectedCircle.pipe(circle=> [ cicle.color ]);

evtSelectedCircleColor.attach(console.log);
```

## Converting an `Evt` into a `StatefulEvt`

Use the method method .toStateful(initialState) of Evt. Example:

```typescript
import { Evt } from "evt";


const evtClickCount= Evt.from(document,"click")
    .pipe([(...[,count])=>[count+1],0])
    .toStateful(0);

//...user click 3 times on the page

console.log(evtClickCount.state); //Prints "3"
```

{% hint style="success" %}
You do not need to pass an initialization value to `.toStateful(),` if you don't the state will be initialized with `undefined` and the returned StatefulEvt will be of type`<T | undefined>`. This is usefull when using .toStateful after `Evt.merge()`. See next example.
{% endhint %}

## Merging multiple `StatefulEvt`s

```typescript
import { Evt } from "evt";

const evtIsBlue= Evt.create(false);
const evtIsBig= Evt.create(false);

const evtIsBigAndBlue = Evt.merge([
    evtIsBlue.evtChange,
    evtIsBig.evtChange
])
    .toStateful()
    .pipe(()=> [ evtIsBlue.state && evtIsBig.state ])
    ;

console.log(evtIsBigAndBlue.state); // Prints "false"

evtIsBlue.state= true;

console.log(evtIsBigAndBlue.state); // Prints "false"

evtIsBig.state= true;

console.log(evtIsBigAndBlue.state); // Prints "true"
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-22pavm?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

## Make a `StatefulEvt` readonly

To prevent a StatefulEvt to be posted by parts of the code that is not supposed to StatefulEvt can be exposed as `StatefulReadonlyEvt`.

```typescript
import { StatefulEvt, StatefulReadonlyEvt } from "evt";

//Return an event that post every second.
function generateEvtTick(delay: number): StatefulReadonlyEvt<number> {

    const evtTick= new StatefulEvt(0);

    setInterval(()=> evtTick.state++, delay);

    retrun evtTick;

}

const evtTick= generateTick(1000);


evtTick.state++; // TS ERROR
evtTick.post(2); // TS ERROR
```

## `.postFoceChange()`

```typescript
 /** 
  * Post and enforce that .evtChange and .evtChangeDiff 
  * be posted even if the state has not changed.
  * 
  * If no argument is passed the post is performed with the current state.
  * 
  * Returns post count 
  **/
  postForceChange(wData?: readonly [T]): number;
```

## `.toStateless([ctx])`

Return a stateless copy of the `Evt.`

```typescript
import { Evt } from "evt";

const evtText= Evt.create("foo");

//x is Evt<string>
const x= evtText.toStateless();
```

`evt.toStateless()` is equivalent to `Evt.prototype.pipe.call(evt)`


# Helper types

## ToNonPostableEvt\<E>

{% hint style="info" %}
`NonPostableEvt<T>` and `StatefulReadonlyEvt<T>` are interfaces implemented respectively by the classes `Evt<T>` and `StatefulEvt<T>`. They contains all the methods but the ones used to post events, namely: `.post(), .postOnceHandled()` and the `.state` setter for `StatefulReadonlyEvt`
{% endhint %}

```typescript
import { ToNonPostableEvt } from "evt";

ToNonPostableEvt<Evt<T>>         → NonPostableEvt<T>
ToNonPostableEvt<SatefulEvt<T>>  → StatefulReadonlyEvt<T>
ToNonPostable<VoidEvt>           → NonPostable<Void>
ToNonPostable<NonpostableEvt<T>> → NonPostableEvt<T>

ToNonPostableEvt<{ 
    evtText: Evt<string>; 
    evtCount: StatefulEvt<number>; 
    type: "FOO" 
}> 
 → 
{ 
    evtText: NonPostableEvt<string>; 
    evtCount: StatefulNonpostableEvt<number>; 
    type: "FOO"
}
```

Example use of the `NonPostableEvt` interface:

```typescript
import { Evt, NonPostableEvt } from "evt";

const evtText= new Evt<string>();

//Api to expose.
export const api:{ evtText: NonPostableEvt<string>; } = { evtText };

//evtText exposed by the api cannot be posted…
api.evtText.post //<=== TS error 
api.evtText.postOnceMatched //<===== TS error

//…but we can post internally.
evtText.post("good");
```

[**Run the example**](https://stackblitz.com/edit/evt-xc2eqj?embed=1\&file=index.ts\&hideExplorer=1)

## **ToPostableEvt\<E>**

Invert of `ToNonPostableEvt`

```typescript
import { 
    ToPostableEvt, 
    NonPostableEvt, 
    StatefulReadonlyEvt
} from "evt";

ToPostableEvt<NonPostableEvt<T>>         → Evt<T>
ToPostableEvt<StatefulReadonlyEvt<T>>    → StatefulEvt<T>
ToPostable<NonPostable<void>>            → VoidEvt
ToPostable<Evt<T>>                       → Evt<T>

ToPostableEvt<{ 
    evtText: NonPostableEvt<string>; 
    evtCount: StatefulReadonlyEvt<number>; 
    type: "FOO" 
}> 
 → 
{ 
    evtText: Evt<string>; 
    evtCount: StatefulEvt<number>; 
    type: "FOO"
}
```

## UnpackEvt\<E>

Extract the type argument of an Evt

```typescript
import { UnpackEvt } from "evt";

UnpackEvt<Evt<number>>            → number
UnpackEvt<StatefulEvt<number>>    → number
UnpackEvt<NonpostableEvt<number>> → number

UnpackEvt<{ 
    evtText: Evt<string>; 
    evtCount: StatefulEvt<number>; 
    type: "FOO" 
}> 
 → 
{ 
    evtText: string; 
    evtCount: number; 
    type: "FOO"
}
```

### Example:

UnpackEvt is a helper type to infer the type argument of an Evt instance.

```typescript
import { Evt, UnpackEvt } from "evt";

const evtHuman = new Evt<{
    name: string;
    age: number;
    gender: "MALE" | "FEMALE"
}>();


type Human = UnpackEvt<typeof evtHuman>;

const human: Human = {
    "name": "bob",
    "age": 89,
    "gender": "MALE"
};

evtHuman.post(human);
```

[**Run the example**](https://stackblitz.com/edit/evt-ykjacd?embed=1\&file=index.ts\&hideExplorer=1)

## SwapEvtType\<E, T>

```typescript
import { SwapEvtType } from "evt";

SwapEvtType<Evt<string>, number>          → Evt<number>
SwapEvtType<SatefulEvt<string>, number>   → SatefulEvt<number>
SwapEvtType<Evt<number>, void>            → VoidEvt
SwapEvtType<StatefulEvt<number>, void>    → VoidEvt
```

## FactorizeEvt\<E>

```typescript
import { FactorizeEvt } from "evt";

FactorizeEvt<Evt<string> | Evt<number>>     → Evt<string | number>
//...Work as well with StatefulEvt, NonPostable ect
```


# Handler\<T, U> (type)

Every time [`attach*`](https://docs.ts-evt.dev/api/evt/evt.attach), [`waitFor`](https://docs.evt.land/api/evt/waitfor) or [`pipe`](https://docs.evt.land/api/evt/pipe) is invoked a new [`Handler<T, U>`](https://docs.evt.land/api/handler) is attached to the [`Evt<T>`](https://docs.evt.land/api/evt).

Handlers can be listed using the [`evt.getHandler()`](https://docs.evt.land/api/evt/evt.gethandler) method.

```typescript
type Handler<T,U> = {

    //Method for detaching the handler from the Evt, returns false if 
    //if invoked when the handler is no longer attached.
    detach(): boolean;

    //The promise returned by the attach*() and waitFor() method.
    promise: Promise<U>;


    /* Properties that depends on the method used to attach the handler */

    //true if the handler was attached using a method containing "prepend"
    //in it's name. Example: evt.$attachOncePrepend(...)
    prepend: boolean;

    //... if the method contained "extract"
    extract: boolean;

    //... if the method contained "once"
    once: boolean;

    //if the method was waitFor()
    async: boolean;



    /* Properties passed as argument to the method used to attach the handler */

    //Default: ()=> true, a filter that matches all events.
    op: Operator<T,U>; 

    //Default: undefined
    ctx?: Ctx; 

    //Default: undefined.
    timeout?: number;

    //Undefined only when the handler was attached using evt.waitFor()
    callback?: (transformedData: U)=> void;

};
```

## Glossary relative to handers:

* An event is said to be **matched** by a handler if posting it causes the callback to be invoked. In practice this is the case when the handler's operator returns true or \[ value, ].
* An event is said to be **handled** by a handler if the event data is matched or if posting it causes the handler and/or other potential handlers to be detached. In practice this is the case when the handler's operator returns `"DETACH"` or `{DETACH: Ctx}.` It is possible to test if a given event data is handled by at least one of the handlers attached to an Evt\<T> by using the [`evt.isHandled(data)`](https://docs.ts-evt.dev/api/evt/evt.ishandled) method.


# React hooks

Evt let you work with events in react without having to worry about cleaning up afterward.

## useEvt()

```tsx
import { useState } from "react";
import { Evt } from "evt";
import { useEvt } from "evt/hooks";

const evtTick = Evt.create();

setInterval(()=> evtTick.post(), 1000);

function App(){

    const [count, setCount]= useState(0);

    useEvt(ctx=> {
    
        evtTick.attach(ctx, ()=> setCount(count+1));
    
    },[count]);
    
    return <h1>tick count: {count}</h1>;

}
```

[**Run it**](https://stackblitz.com/edit/evt-hooks-101?file=index.tsx)

{% hint style="success" %}
The core idea is to always use the `ctx` to attach handlers. This will enable EVT to detach/reload handlers when they need to be namely when the component is unmounted or a value used in a handler has changed.
{% endhint %}

## useRerenderOnStateChange()

```tsx
import { useState } from "react";
import { Evt } from "evt";
import { useRerenderOnStateChange } from "evt/hooks";

const evtTickCount = Evt.create(0);

setInterval(()=> evtTickCount.state++, 1000);

function App(){

    useRerenderOnStateChange(evtTickCount);
    
    return <h1>tick count: {evtTickCount.state}</h1>;

}
```

## ESLint

You can use this [`react-hooks/exhaustive-deps`](https://github.com/facebook/react/blob/master/packages/eslint-plugin-react-hooks/README.md#advanced-configuration) to be warned if you forget a dependency:

```javascript
//package.json (if you use create-react-app otherwise use .eslintrc.js) 
{
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ],
    "rules": {
      "react-hooks/rules-of-hooks": "error",
      "react-hooks/exhaustive-deps": [
        "error",
        {
          "additionalHooks": "(useEvt)"
        }
      ]
    }
  }
}
```


# Extending Evt

It is common practice to create classes that extends `EventEmitter` .&#x20;

As a general rule of thumb, we tend to avoid inheritance in favor of other patterns but if you want to do it there is how.

```typescript
import { Evt, to } from "evt";

class MySocket extends Evt<
    ["connect", void] |
    ["disconnect", { cause: "remote" | "local" } ] |
    ["error", Error]
    > {

    public readonly address: string;

    constructor(
        params: { 
            address: string; 
        }
    ) {

        super();

        const { address } = params;

        this.address = address;

        setTimeout(
            () => this.post(["connect", undefined]),
            300
        );

        setTimeout(
            () => this.post(["disconnect", { "cause": "local" }]),
            2000
        );

    }

}



const socket = new MySocket({ 
    "address": "wss://example.com"
});

(async ()=> {

  await socket.waitFor(to("connect"));

  console.log("Socket connected");

})();

socket.$attach(to("error"), error => { throw error });

socket.$attach(
    data=> data[0] === "disconnect" ? [ data[1] ] : null, //Just so you know this is what the to() operator do
    ({ cause })=> console.log(`socket disconnect (${cause})`)
);
```

[**Run the browser**](https://stackblitz.com/edit/evt-inheritence-pdzywu?file=index.ts)

Now we encourage favoring composition over inheritance and having one EVT instance for each events type.

```typescript
import { Evt } from "evt";
import type { NonPostableEvt } from "evt";

class MySocket {

    public readonly address: string;
    
    /*
    We use NonPostableEvt instead of Evt so we make clear that
    the connect disconnect and error events are not supposed to
    be posted from outside the class implementation.
    */

    public readonly evtConnect: NonPostableEvt<void> = new Evt();
    
    //Equivalent of the line above but it prevent you from having to import the ToNonPostable helper type
    public readonly evtDisconnect = Evt.asNonPostable(
        Evt.create<{ 
            cause: "local" | "remote" 
        }>()
    ); 
    
    public readonly evtError= Evt.asNonPostable(
        Evt.create<Error>()
    );

    constructor(
        params: { 
            address: string; 
        }
    ) {

        const { address } = params;

        this.address = address;


        setTimeout(
            () => Evt.asPostable(this.evtConnect).post(),
            300
        );

        setTimeout(
            () => Evt.asPostable(this.evtDisconnect).post({ "cause": "local" }),
            2000
        );

    }

}

const socket = new MySocket({ 
    "address": "wss://example.com"
});

(async ()=> {

  await socket.evtConnect.waitFor();

  console.log("socket connected [bis]");

})();

socket.evtError.attach(error => { throw error });

socket.evtDisconnect.attach(
    ({ cause }) => console.log(`socket disconnect (${cause})`)
);
```

[**Run in the browser**](https://stackblitz.com/edit/evt-inheritence-mnhwcs?file=index.ts)


# EVT Overview

{% embed url="<https://stackblitz.com/edit/evt-playground-gfnidx?file=index.ts>" %}
Basic usage
{% endembed %}

{% embed url="<https://stackblitz.com/edit/evt-playground-acvrn5?file=index.ts>" %}
wait for the next event
{% endembed %}

{% embed url="<https://stackblitz.com/edit/evt-playground-t9i9fr?file=index.ts>" %}
Filtering the events
{% endembed %}

{% embed url="<https://stackblitz.com/edit/evt-playground-kjdjdh?file=index.ts>" %}
Detaching handler
{% endembed %}

{% embed url="<https://stackblitz.com/edit/evt-playground-wsa3je?file=index.ts>" %}
Evt that saves the last event
{% endembed %}


# API Documentation

The API reference documentation of the library and step-by-step guide for new users.


# Evt\<T>

Evt\<T> is the Class that is the equivalent of EventEmitter in "events" and Subject\<T> in "rxjs"

The method's documentation pages are ordered so that you get the more important information first.


# Async iterator

An `Evt` is an `AsyncIterable`: &#x20;

{% embed url="<https://stackblitz.com/edit/evt-playground-uvjd74?file=index.ts>" %}

You can stop the loop from outside by using a `Ctx`

{% embed url="<https://stackblitz.com/edit/evt-playground-xw66az?file=index.ts>" %}

You can automatically exit the loop when ever x millisecond have passed since the last event was received.

{% embed url="<https://stackblitz.com/edit/evt-playground-fsbad9?file=index.ts>" %}

You can also filter the type of event you want to iterate over: &#x20;

{% embed url="<https://stackblitz.com/edit/evt-playground-i17pvg?file=index.ts>" %}


# evt.attach\*(...)

Attach a Handler provided with a callback function to the Evt

There is multiple flavor of the attach method: `attachOnce`, `atachPrepend`, `attachExtract`... All this methods have in common to accept the same parameters and to return the same promise.

## The `$` prefix

Due to a current [TypeScript limitation](https://github.com/microsoft/TypeScript/issues/36735) the `.attach*()` methods need to be prefixed with `$` when used with fλ operators but `evt.$attach*()` are actually just aliases to the corresponding `evt.attach*()` methods.

```typescript
import { Evt } from "evt";

const evtText= new Evt<string>();


//No operator, we don't need the $ prefix
evtText.attach(text => console.log(`1: ${text}`));

//text => text.startWith("H") is a filter so we do not need the $ prefix
evtText.attach(
    text => text.startWith("H"),
    text => console.log(`2: ${text}`)
);

//text => [ text.toUpperCase() ] is a fλ operator, we need the $ prefix
evtText.$attach(
    text => [ text.toUpperCase() ],
    upperCaseText => console.log(`3: ${upperCaseText}`)
);

//Prints: 
//"1: Hello World" 
//"2: HelloWorld"
//"3: Hello World"
evtText.post("Hello World");


```

## Parameters

1. `operator:` [`Operator`](https://docs.ts-evt.dev/api-doc/operator)`<T,U>`
2. `timeout: number` Amount of time, in milliseconds before the returned promise rejects if no event has been matched within the specified delay.
3. `ctx:` [`Ctx`](https://docs.ts-evt.dev/api/ctx)A context that can be used as a reference to detach the handler later on.&#x20;
4. `callback: (data: U)=> void` Function that will be invoked every time the matcher match an event emitted by the `Evt`.

A large number of overload is provided to cover all the possible combination of arguments. The ordering in which the parameters are listed above must be respected but every parameter other than the callback can be omitted.

![](/files/-M7sqVfSMPRvTazrJY6r)

Examples:

* Only specifying a timeout: `evt.attach(timeout, callback)`
* Specifying an operator and a context: `evt.attach(op, boundTo, callback)`
* ...

## Returned Value

It no timeout argument have been passed all attach methods return `this`.

If a timeout arguement was passed a `Promise<U>` that resolves with the first event data matched by the operator. By default of operator, all the events are matched.

The returned promise can reject **only** if a timeout parameter was passed to the `attach*` method.

If no event has been matched within the specified timeout, the promise will reject with a `EvtError.Timeout.` If the event is detached before the first event is matched, the promise will reject with an `EvtError.Detached`.

If you have no use of the callback function and just want the promise, [`evt.waitFor(...)`](https://docs.ts-evt.dev/api-doc/evt#evt-waitfor) should be used in place of `evt.attach*(...)`.

## **`evt.attach(...)`**

Adds a new [handler](https://docs.ts-evt.dev/api/handler) to the end of the handlers array. No checks are made to see if the holder has already been added. Multiple calls passing the same combination of parameters will result in the `handler` being added, and called, multiple times.

## **`evt.attachOnce*(...)`**

When the method contains the keyword "**once**": Adds a **one-time** [handler](https://docs.ts-evt.dev/api/handler). The next time an event is matched this handler is detached and then it's callback is invoked.

## `evt.attach[Once]Prepend(...)`

When the method contains the keyword "**prepend**": Same as .attach() but the [`handler`](https://docs.ts-evt.dev/api/handler) is added at the *beginning* of the handler array.

```typescript
import { Evt } from "evt";

const evtLetter = Evt.create();

evtLetter
  .attach(() => console.log("B"))
  .attach(() => console.log("C"))
  .attachPrepend(() => console.log("A"))
  ;

evtLetter.post();
//"A", "B", "C" is printed to the console.
```

[**Run the example**](https://stackblitz.com/edit/evt-qshmkh?embed=1\&file=index.ts\&hideExplorer=1)

## **`evt.attach[Once]Extract(...)`**

When the method contains the "**extract**" keyword, every event that the [`handler`](https://docs.ts-evt.dev/api/handler) matches will be swallowed and no other handler will have the opportunity to handle it, even the other "extract"' handlers. It acts as a trap.

"**extract**" handler has priority even over "**prepend**" [`Handler`](https://docs.ts-evt.dev/api/handler)s.

If multiples "extractes" handlers are candidates to extract an event the handler that has been added first have priority.

```typescript
import { Evt } from "evt";

const evtCircle = new Evt<Circle>();

evtCircle.attachExtract(
    ({ radius }) => radius <= 0,
    ({ radius }) => console.log(`Circle with radius: ${radius} extracted`)
);

evtCircle.attach(
    circle => {
        //We can assume that the circle has a positive radius.
        console.assert(circle.radius > 0);
    }
);

//Extract have priority over prepend
evtCircle.attachPrepend(
    circle => console.assert(circle.radius > 0)
);
```

[**Run the example**](https://stackblitz.com/edit/evt-bwkprd?embed=1\&file=index.ts\&hideExplorer=1)


# evt.post\*(data)

## **`evt.post(data)`**

Equivalent of `eventEmitter.emit()` and `subject.next()`.

Returns evt.postCount

## **`evt.postCount: number`**

The number of times `evt.post()` has been called. It's a read-only property.

```typescript
import { Evt } from "evt";

const evtText= new Evt<string>();

//prints 0
console.log(evtText.postCount);

evtText.post("foo");
evtText.post("bar");
evtText.post("baz");

//prints 3
console.log(evtText.postCount);
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-2npimn?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

## `evt.postAsyncOnceHandled(data)`

Post the event data only once there is at least one handler candidate to handle it.

When `evt.isHandled(data)` return `true`, `post(data)` is invoked synchronously and the new post count is returned. When `postAsyncOnceHandled(data)` is invoked at a time where`evt.isHandled(data)` returns `false`, the `data` will be kept on hold and posted only once a candidate handler is attached.

`evt.post(data)` is not invoked synchronously as soon as the candidate handler is attached but is scheduled to be invoked in a microtask.\
When the call to post is delayed `postAsyncOnceHandled(data)` returns a promise that resolves with the new post count after `post(data)` has been invoked.

```typescript
import { Evt } from "evt";

function createPreloadedEvtText(): Evt<string>{

    const evtText = new Evt<string>();

    (async ()=>{

        await evtText.postAsyncOnceHandled("foo");
        evtText.post("bar");

    })();


    return evtText;

}

const evtText = createPreloadedEvtText();

evtText.attach(text => console.log("1 " + text));
evtText.attach(text => console.log("2 " + text));

console.log("BEFORE");

//"BEFORE" then (next micro task) "1 foo" "2 foo" "1 bar" "2 bar"
```

[**Run the example**](https://stackblitz.com/edit/evt-mycz4t?embed=1\&file=index.ts\&hideExplorer=1)

{% hint style="info" %}
`evt.postSyncOnceHandled()` does not exist because it is preferable to wait for the next event cycle before posting the event. For example, the previous example would not print `"2 foo"` if we had used `evt.postSyncOnceHandled()`
{% endhint %}

## `evt.postAndWait(data): Promise<void>`

Flavor of post that returns a promise that resolves after all asynchronous Handler's callbacks that matches the event data has resolved.

```typescript
import { Evt } from "evt";

const evt = Evt.create();

evt.attach(async () => {

    await new Promise(resolve => setTimeout(resolve, 100));

    console.log("bar");

});

(async () => {

    console.log("foo");

    await evt.postAndWait();

    console.log("baz");


})();

//"foo bar baz" is printed to the console.
```


# evt.waitFor(...)

Method that returns a promise that will resolve when the next matched event is posted.

## Without timeout

By default the promise returned by `waitFor` will never reject.

```typescript
import { Evt } from "evt";

const evtText = Evt.create<string>();

setTimeout(()=> evtText.post("Hi!"), 1500);

(async ()=>{

    //waitFor return a promise that will resolve next time 
    //post() is invoked on evtText.
    const text = await evtText.waitFor();

    console.log(text);

})();
```

[**Run the example**](https://stackblitz.com/edit/evt-cazqyr?embed=1\&file=index.ts\&hideExplorer=1)

## With timeout

As with `attach*`, it is possible to set what is the maximum amount of time we are willing to wait for the event before the promise rejects.

```typescript
import { Evt, TimeoutEvtError } from "evt";

const evtText = Evt.create<string>();

(async ()=>{

    try{

        const text = await evtText.waitFor(500);

        console.log(text);

    }catch(error){

        console.assert(error instanceof TimeoutEvtError);
        //Error can be of two type:
        //  -EvtError.Timeout if the timeout delay was reached.
        //  -EvtError.Detached if the handler was detached before 
        //  the promise returned by waitFor have resolved. 

        console.log("TIMEOUT!");

    }

})();

//A random integer between 0 and 1000
const timeout= ~~(Math.random() * 1000);

//There is a fifty-fifty chance "Hi!" is printed else it will be "TIMEOUT!".
setTimeout(
    ()=> evtText.post("Hi!"), 
    timeout
);
```

[**Run the example**](https://stackblitz.com/edit/evt-wqh856?embed=1\&file=index.ts\&hideExplorer=1)

## Subtilities of `evt.waitFor(...)`&#x20;

```typescript
import { Evt } from "evt";

const evtText = Evt.create<string>();

(async ()=>{

    //const firstLetter = await new Promise(resolve=> evtText.attachOnce(resolve));
    const firstLetter = await evtText.waitFor();
    //const secondLetter = await new Promise(resolve=> evtText.attachOnce(resolve));
    const secondLetter = await evtText.waitFor();


    console.log(`${firstLetter} ${secondLetter}`);

})();

evtText.post("A");
evtText.post("B");

//"A B" is printed to the console.  
// Now, if you comment out the implementation using .attachOnce you'll see that
// the second letter is lost, we never reach the console.log
```

[Playground](https://stackblitz.com/edit/evt-playground-34zdzv?file=index.ts)


# evt.evt\[Attach|Detach]

`evt.evtAttach` and `evt.evtDetach` are accessors for `Evt<Handler<T, any>>` that posts every time a new handler is attached to/detached from the `Evt<T>`.

```typescript
import { Evt } from "evt";

const evtText= new Evt<string>();

function myCallback(text: string){};

evtText.getEvtAttach().attach(
    handler=> console.log(`${handler.callback.name} attached`)
);

evtText.getEvtDetach().attach(
    handler=> console.log(`${handler.callback.name} detached`)
);

//"myCallback attached" is printed to the console.
evtText.attach(callback);

//"myCallback detached" is printed to the console.
evtText.detach();
```

[**Run the example**](https://stackblitz.com/edit/evt-xwe67h?embed=1\&file=index.ts\&hideExplorer=1)


# evt.pipe(...)

An alternative to compose for chaining operaors.

{% hint style="warning" %}
Being familiar with [`Ctx`](https://docs.evt.land/api/ctx) and [`Operator`](https://docs.evt.land/api/operator)is a prerequisite for properly using pipe.
{% endhint %}

## Return

A new Evt instance toward which are forwarded the transformed events matched by the operator(s).

## Parameters

`Ctx`: Optional, the context to which will be bound the handler responsible for forwarding events to the returned Evt.

`...Operator[]`: One or many operators composable with one another.

## Examples

There are two ways of using pipe, the first is to call pipe only once and passing it all the operators to chain, the second is to chain the `pipe` calls providing each time a single operator. Depending on the situation, you should favor one approach over the other.

Let us consider a case where the two approaches are equally valid.

Using a single call to `pipe`:

```typescript
import { Evt } from "evt";

type Circle = { type: "CIRCLE"; radius: number; };
type Square = { type: "SQUARE"; sideLength: number; };
type Shape = Circle | Square;

const evtShape = new Evt<Shape | undefined>();

evtShape.pipe(
    shape => !shape ? null : [ shape ], // Filter out undefined
    shape => shape.type !== "CIRCLE" ? null : [ shape ], // Filter Circle
    ({ radius }) => [ radius ], // Extract radius
    radius => radius > 200 ? "DETACH": [ radius ] //Detach if radius too large 
).attach(radius=> { /* ... */ });
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-jx2nnm?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

Same thing chaining `pipe`:

```typescript
const evtShape = new Evt<Shape | undefined>();

const ctx= Evt.newCtx();

evtShape
    .pipe(ctx)
    .pipe(shape => !shape ? null : [ shape ])
    .pipe(shape => shape.type !== "CIRCLE" ? null : [ shape ])
    .pipe(({ radius }) => [ radius ])
    .pipe(radius => radius > 200 ? { "DETACH": ctx } : [radius])
    .attach(radius => { /* ... */ });
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-yb4gzb?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

{% hint style="danger" %}
When chaining `pipe` if one operator in the midle of the chain returns `"DETACH"` all the handler upstream will stay attached. You must always detach the first link of the chain using a [`Ctx`](https://docs.evt.land/api/ctx).
{% endhint %}

The first approach (calling pipe only once) is preferable as it is slightly less verbose but in some cases you will reach the limits of TypeScript inference capabilities especially if you throw filters and generic operators into the mix. Bottom point is: try the first method, see how TypeScript infer the types, if detection fails fallback to chainging `pipe()`.

### Creating delegates

Pipe can also be used to create proxies to a source `Evt`.

```typescript
import { Evt } from "evt";

const evtShape = new Evt<Shape>();

//evtCircle is of type Evt<Circle> because matchCircle is a type guard.
const evtCircle = evtShape.pipe(matchCircle);

//evtLargeShape is of type Evt<Shape>
const evtLargeShape = evtShape.pipe(shape => {
  switch (shape.type) {
    case "CIRCLE":
      return shape.radius > 5;
    case "SQUARE":
      return shape.sideLength > 3;
  }
});

evtCircle.attach(({ radius }) =>
  console.log(`Got a circle, radius: ${radius}`)
);

evtLargeShape.attach(
    shape => console.log(`Got a large ${shape.type}`)
);

//"Got a circle, radius: 66" and "Got a large CIRCLE" will be printed.
evtShape.post({
  "type": "CIRCLE",
  "radius": 66
});

//Only "Got a circle, radius: 3" will be printed
evtShape.post({
  "type": "CIRCLE",
  "radius": 3
});

//Only "Got a large SQUARE" will be printed
evtShape.post({
  "type": "SQUARE",
  "sideLength": 30
});

//Nothing will be printed
evtShape.post({
  "type": "SQUARE",
  "sideLength": 1
});
```

[**Run the example**](https://stackblitz.com/edit/evt-e9zjnq?embed=1\&file=index.ts\&hideExplorer=1)


# evt.getHandlers()

List all handlers attached to the `Evt`. Returns an array of [`Handler<T,any>`](https://docs.ts-evt.dev/api/handler).

Here a use case detaching all handlers that uses a given matcher:

```typescript
import { Evt } from "evt";

const evtShape = new Evt<Shape>();

evtShape.attach(
    matchCircle,
    circle => console.log("1:", circle)
);

evtShape.attachOnce(
    matchCircle,
    circle => console.log("2:", circle)
);

evtShape.waitFor(matchCircle)
    .then(circle => console.log("3:", circle))
    ;

//Only handler that does not use matchCircle as operator.
evtShape.attach(circle => console.log("4:", circle))


evtShape.getHandlers()
    .filter(({ op }) => op === matchCircle)
    .forEach(({ detach }) => detach())
    ;

//Prints only "4: ..." other handlers are detached.
evtShape.post({ "type": "CIRCLE", "radius": 300 });
```

[**Run the example**](https://stackblitz.com/edit/evt-zufivp?embed=1\&file=index.ts\&hideExplorer=1)

### `Equivalent of EventEmitter's handler.detach(callback)`

To detach all the handlers using a given callback function as we do with `EventEmitter`:

```typescript
import { Evt } from "evt";

const evtText = new Evt<string>();

const callback = (text: string) => console.log(text);

evtText.attach(callback);

evtText.post("Foo"); //Prints "Foo"

evtText.getHandlers()
    .filter(handler => handler.callback === callback)
    .forEach(({detach})=> detach())
    ;

evtText.post("Foo"); //Prints nothing
```

[**Run the example**](https://stackblitz.com/edit/evt-wrqoct?embed=1\&file=index.ts\&hideExplorer=1)


# evt.isHandled(data)

Return true if:

* There is at least one handler matching this event data ( at least one handler's callback function will be invoked if the data is posted. )
* There is at least one handler that will be detached if the event data is posted.

```typescript
const evtText = new Evt<string>();

/*
Handle the text starting with 'h'.
Ignore all other text, when a text starting with 'g'
is posted the handler is detached
*/
evtText.$attach(
    text=> text.startsWith("h") ? 
        [ text ] : 
        text.startsWith("g") ? "DETACH" : null,
    text=> {/* do something with the text */}
);

//"true", start with 'h'
console.log(
    evtText.isHandled("hello world")
);

//"false", do not start with 'h' or 'g'
console.log(
    evtText.isHandled("foo bar")
);

//"true", not matched but will cause the handler to be detached if posted
console.log(
    evtText.isHandled("goodby world")
);
```

[**Run the example**](https://stackblitz.com/edit/evt-a3m4od?embed=1\&file=index.ts\&hideExplorer=1)


# evt.detach(ctx?)

Similar to EventEmitter.prototype.removeListener()

Detach all handlers from the Evt or all Evt's handler that are bound to a given context.

{% hint style="info" %}
The prefered way of detaching handler in TS-EVT is via [`Ctx<T>`](https://docs.ts-evt.dev/api/ctx) .
{% endhint %}

{% hint style="warning" %}
Calling this method without passing a context argument is almost never a good idea. An Evt instance should be sharable by modules that are isolated one another. If a module take the liberty to call evt.detach() it can brek the code elswhere.
{% endhint %}

{% hint style="info" %}
To chery pick the handlers to detach use [`evt.getHandlers()`](https://docs.ts-evt.dev/api/evt/evt.gethandler) or [`ctx.getHandlers()`](https://docs.ts-evt.dev/api/ctx#ctx-gethandlers)\`\`
{% endhint %}

## Returns

`Handler<T,any>[]` array of Handler that have been detached.

## Parameters

`ctx?: Ctx` If [`Ctx`](https://docs.ts-evt.dev/api/ctx) is provided only Handler bound to the given context will be removed.

## Examples

To detach all handlers at once:

```typescript
const evtText = new Evt<string>();
//detach with no argument will detach all handlers (attach, attachOnce, waitFor... )
evtText.detach();
```

Using a context argument

```typescript
import { Evt } from "evt";

const evtText = new Evt<string>();

evtText.attachOnce(text=> console.log(`Hello ${text}`));

const ctx = Evt.newCtx();

evtText.attach(
    ctx,
    _text => console.assert(false,"never")
);

evtText.attachOnce(
    ctx,
    _text => console.assert(false,"never")
);

evtText.detach(ctx);

//"Hello World" will be printed
evtText.post("World");
```

[**Run the example**](https://stackblitz.com/edit/evt-bhxla6?embed=1\&file=index.ts\&hideExplorer=1)


# evt.enableTrace(...)

If you need help to track down a bug, you can use `enableTrace` to log what's going on with an Evt.\
Use `evt.disableTrace()` to stop logging.

```typescript
import { Evt } from "evt";

{
    const evtCircle = new Evt<Circle>();

    evtCircle.enableTrace({ "id": "evtCircle n°1" });

    evtCircle.post(circle1);

    evtCircle.attachOnce(circle => {});

    evtCircle.post(circle2);

}

console.log("\n");

//Optional arguments 
{

    const evtCircle = new Evt<Circle>();

    evtCircle.enableTrace({
        "id": "evtCircle n°2",
        "formatter": circle => `CIRCLE(${circle.radius})`,
        "log": (...args)=> console.log(...["[myPrefix]",...args]) 
        // ^Log function default console log
    );

    evtCircle.attach(
        ({ radius }) => radius > 15, 
        circle => {}
    );

    evtCircle.post(circle1);
    evtCircle.post(circle2);

}
```

This will print:

```
(evtCircle n°1) 0 handler, { "type": "CIRCLE", "radius": 12 }
(evtCircle n°1) 1 handler, { "type": "CIRCLE", "radius": 33 }

[myPrefix] (evtCircle n°2) 0 handler, CIRCLE(12)
[myPrefix] (evtCircle n°2) 1 handler, CIRCLE(33)
```

[**Run the example**](https://stackblitz.com/edit/evt-vfjvfs?embed=1\&file=index.ts\&hideExplorer=1)


# evt.setMaxHandlers(n)

By default `Evt` will print a warning if more than 25 handlers are added. This is a useful default that helps finding memory leaks. Not all events should be limited to 25 handlers. The `evt.setMaxHandlers()` method allows the limit to be modified for this specific `Evt` instance. ( Use the static method [`Evt.setDefaultMaxHandlers()`](https://docs.evt.land/api/evt/setdefaultmaxhandlers) to change this limit globally.

The value can be set to `Infinity` (or 0) to indicate an unlimited number of listeners.

Returns a reference to the Evt, so that calls can be chained.


# toStateful(initialState)

See [StatefulEvt\<T>](https://docs.evt.land/api/statefulevt#converting-an-evt-into-a-statefulevt)


# evt.getStatelessOp(op)

{% hint style="warning" %}
This is an advanced feature, it you are new to EVT you can skip this for now.
{% endhint %}

It is not always possible to manually invoke an operator attached to an Handler that you got using `evt.getHandlers()`. Indeed if the operator is stateful you can't provide the `prev` value. This function gives access to this state.

Because it is such an advanced feature we just provide an example as documentation:

```typescript
//invokeOperator allow calling any type of stateless operator and 
//get a return as if the operator was a fλ
import { Evt, invokeOperator } from “evt”;


{

    const evtPoint = new Evt<number>();

    evtPoint.$attach(
        [(point, sum) => [point + sum], 0],
        sum => console.log(`sum: ${sum}`)
    );

    evtPoint.post(2); // Prints "sum: 2"

    console.log(
        invokeOperator(
            evtPoint.getStatelessOp(
                evtPoint.getHandlers()[0].op
            ),
            2
        )
    ); // Prints "[ 4 ]" ( 2 + 2 )

    evtPoint.post(3); // Prints "sum: 5" ( the state was not affected )

}

{

    const evtPoint = new Evt<number>();

    evtPoint.attach(
        point => point > 10,
        point => { } 
    );

    console.log(
        invokeOperator(
            evtPoint.getStatelessOp(
                evtPoint.getHandlers()[0].op
            ),
            5
        )
    ); // Prints "null" ( 5 < 10 )

    console.log(
        invokeOperator(
            evtPoint.getStatelessOp(
                evtPoint.getHandlers()[0].op
            ),
            15
        )
    ); // Prints "[ 15 ]" ( 15 > 10 )

}
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-yljxhq?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*


# Evt.create(initalState?)

Static method to instanciate an Evt or a StatefulEvt.

Evt.create() is the prefered method for instantiating an Evt as this single method allow to instantiate Evt, StatefulEvt and VoidEvt.

{% hint style="info" %}
The constructors are still useful however to avoid repeating the type of variable that are already typed e.g: `const evt: Evt<string | number> = new Evt()`
{% endhint %}

## Usage

```typescript
import { Evt, VoidEvt, StatefulEvt } from "evt";

Evt.create<string>()     ⇔     new Evt<string>()
Evt.create()             ⇔     /* An object that implement VoidEvt */
Evt.create(false)        ⇔     new StatefulEvt<boolean>(false)
```

## Why `VoidEvt` and not `Evt<void>` ?

When you instantiate an `Evt` with a void argument ( `new Evt<void>()` ), TypeScript forces you to pass `undefined` to the post method ( it does not allows to call `evt.post()` ).\
`VoidEvt` ( and respectively `VoidCtx` ) is a workaround for this annoyance.

`VoidEvt` object are instances of `Evt<void>` that you can post without passing argument.

```typescript
import { Evt } from "evt";

const evtSocketConnect = Evt.create();

evtSocketConnect.attach(() => console.log("SOCKET CONNECTED"));

evtSocketConnect.post();
//"SOCKET CONNECTED" have been printed on the console.
```


# Evt.newCtx\<T>()

Get a new instance of Ctx

The recommended way to get a new [`Ctx`](https://docs.ts-evt.dev/api/ctx) instance. The type argument is optional, default is void.

## Returns

* [`Ctx<T>`](https://docs.ts-evt.dev/api/ctx) if a type argument was specified
* [`VoidCtx`](https://docs.ts-evt.dev/api/ctx) if no type argument was speficied.

## Example

```typescript
import { Evt } from "evt";

const ctx = Evt.newCtx();

ctx.getPrDone().then(()=> console.log("DONE"));

ctx.done(); //Prints "DONE"

//----------------------------

const ctxData = Evt.newCtx<Uint8Array>();

ctxText.getPrDone().then(
    data=> console.log(`DONE: ${data.byteLength} bytes`)
);

ctxText.done(new Uint8Array([1,2,3])); //Prints "DONE: 3 bytes"
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-5xs5rr?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*


# Evt.getCtx(object)

A way to avoid having to create a ctx variable.

`Evt.getCtx(obj)` return an instance of `Ctx<void>`, always the same instance for a given object. Iternally it's a `WeakMap<any, Ctx>`.

No strong reference to the object is created when the object is no longer referenced it's associated Ctx will be freed from memory.


# Evt.from\<T>(...)

Creates an Evt that post events of a specific type coming from other API that emmits events.

## Returns

Evt\<T> will post every time the emitter emits

## Parameters

Ctx Optional, Allows detaching the handlers attached to the source emitter.

`emitter`: Any of the following,

* DOM EventTarget
* [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)
* Node.js EventEmitter
* JQuery-like event target
* RxJS Subject
* An Array, NodeList or HTMLCollection of many of these.
* A promise

Depending of the API the type argument will be inferred or not.

`name`: The event name of interest, being emitted by the `target`.

## Examples

### With DOM EventTarget

```typescript
import { Evt } from "evt";

Evt.from(document, "click").attach(mouseEvent=> {/*...*/});

const ctx = Evt.newCtx();

Evt.from(ctx, document, "wheel").attach(wheelEvent=> {/*...*/});
```

[**Run the example**](https://stackblitz.com/edit/evt-whhtbw?embed=1\&file=index.ts\&hideExplorer=1)

```typescript
declare const htmlButtonElement: HTMLButtonElement;

Evt.from(ctx, htmlButtonElement, "click").attach(mouseEvent => {/* ... */});
```

[**Run the example**](https://stackblitz.com/edit/react-ts-hqhuzk?file=App.tsx)

### From [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)

```typescript
const ctx = Evt.createCtx();
declare const htmlDivElement: HTMLDivElement;

Evt.from(ctx, ResizeObserver, htmlDivElement).attach(resizeObserverEntry=>{/* ... */});
```

### From `EventEmitter`

```typescript
import { Evt } from "evt";
import { EventEmitter } from "events";

const ctx= Evt.newCtx();

const ee= new EventEmitter();
const evtText= Evt.from<string>(ctx, ee, "text");
evtText.attach(text=> console.log(text));

evtText.post("Foo bar");//Prints "Foo bar";

ctx.done();

console.log(ee.listenerCount("text"));//Prints "0"
```

[**Run the example**](https://stackblitz.com/edit/evt-qyk2ny?embed=1\&file=index.ts\&hideExplorer=1)

### With RxJS Subject

```typescript
import { Evt } from "evt";
import { Subject } from "rxjs";

const ctx= Evt.newCtx();

const subject = new Subject<string>();

const evtText = Evt.from(ctx, subject); //The type argument is inferred.

evtText.attach(text=> console.log(text));

subject.next("Foo bar"); //Prints "Foo bar"

ctx.done();

subject.next("Foo bar"); //Prints nothing
```

[**Run the example**](https://stackblitz.com/edit/evt-t14cot?embed=1\&file=index.ts\&hideExplorer=1)

### With JQuery-like event target

```typescript
import { Evt } from "evt";

Evt.from([
    $("#btnA"),
    $("#btnB"),
    $("#btnC")
], "click").attach(()=> console.log("Clicked!"));
```


# Evt.merge(\[ evt1, evt2, ... ])

Returns a new `Evt` instance which concurrently post all event data from every given input `Evt`.

## Return

A new `Evt` that has for type arguments the union of the type arguments of the inputs `Evt`.

## Parameters

`Ctx<any>` *Optional*, `Ctx` that will be used to detach the handler that has been attached to the input Evts.

`Evt<any>[]` Evts to be merged.

## Example

```typescript
import { Evt } from "evt";

const ctx= Evt.newCtx();

const evtText = new Evt<string>();
const evtTime = new Evt<number>();

//evtTextOrTime is Evt<string | number>, ctx is optional.
const evtTextOrTime= Evt.merge(ctx, [evtText, evtTime]);

evtTextOrTime.attach(console.log);

evtText.post("Foo bar"); //Prints "Foo bar"

ctx.done();

evtText.post("Foo bar"); //Prints nothing
```

[**Run the example**](https://stackblitz.com/edit/evt-nbshnc?embed=1\&file=index.ts\&hideExplorer=1)


# Evt.loosenType(evt)

{% hint style="info" %}
This is the identity function with special type annotations.
{% endhint %}

Swipe the type argument with a superset without giving up type safety.

If `A` is assignable to `B` ⇒ `Evt<A>` is assignable to `Evt<B>`

e.g:`Evt<1|2|3>` is assignable to `Evt<number>` however typescript wont let you do this assignation. This is where `Evt.loosenType` come in handy.

```typescript
import { Evt } from "evt";

declare const evFooBar: Evt<"FOO" | "BAR">; 
declare function myFunc(evtText: Evt<string>): void;

myFunc(evtFooBar); //Gives a type error; 
myFunc(Evt.loosenType(evtFooBar)); //OK
```


# Evt.factorize(evt)

{% hint style="info" %}
This is the identity function with special type annotations.
{% endhint %}

If you have a variable that is either an `Evt` that post `A` or an `Evt` that post `B` you have an event that post `A or B`.

In other words `Evt<A> | Evt<B>` is assignable to `Evt<A | B >.` This method implements this property.

```typescript
import { Evt, VoidEvt, matchVoid } from "evt";

declare evt: Evt<string> | Evt<number> | VoidEvt = Evt.create<any>();

evt.attach(data=> { }); // TS ERROR

Evt.factorize(evt) // OK, return Evt<string | number | void>
    .attach(data=> { // data is string | number | void

        //To test if data is void
        if( matchVoid(data) ){
            return;
        }

        //Here data is string | number.

    })
    ;
```

See also [`FactorizeEvt<E>`](https://docs.evt.land/api/helpertypes#swapevttype-less-than-e-t-greater-than), helper type that this method levrage.


# Evt.asPostable(evt)

Cast the passed event as portable.

## Deprecated

Evt.asPostable() will be removed in the next major of Evt. &#x20;

If you are currently using it, consider refactoring your code so that you don't need it anymore.&#x20;

See [this newer example](/migrating_from_events#composition-recommended-approach). ( that replace [the older one](https://github.com/garronej/evt/blob/2069fe58663433c3042e00a9b72622e244b01721/extending_evt.md?plain=1#L71-L138)).

<pre class="language-diff"><code class="lang-diff"> import { Evt } from "evt";
 import type {
   NonPostableEvt,
<strong>+  ToPostableEvt
</strong> } from "evt";

 const evtMsg: NonPostableEvt&#x3C;string> = new Evt();

<strong>-Evt.toPostable(evtMsg).post("foo");
</strong><strong>+(evtMsg as ToPostable&#x3C;typeof evtMsg>).post("foo");
</strong></code></pre>

## Usecase

{% hint style="info" %}
Evt.asNonPostable() is the identity function with special type annotation
{% endhint %}

{% hint style="warning" %}
Use this method only on`Evt` you instantiated yourself. Not as a hack to trigger events on `Evt` that have been exposed as non-postable by an API.
{% endhint %}

To invoke `post()` on a `NonPostableEvt` or a `StatefullReadonlyEvt`.

Without this method this would be the way for a class to expose `Evt` that are posted internally and exposed to be listened.

```typescript
import { Evt } from "evt";

class Socket2 {

    private readonly _evtIsConnected= Evt.create(false);
    private readonly _evtMessage= Evt.create<Uint8Array>();

    readonly evtIsConnected= Evt.asNonPostable(this._evtIsConnected);
    readonly evtMessage= Evt.asNonPostable(this._evtMessage);

    /* 
        OR, more explicit but require to repeat the types and to
        import type { StatefulReadonlyEvt, NonPostableEvt } from "evt";

    readonly evtIsConnected: StatefulReadonlyEvt<boolean>= this._evtIsConnected;
    readonly evtMessage: NonPostableEvt<Uint8Array> = this._evtMessage;
    */

    constructor(){

        this._evtIsConnected.state = true;
        this._evtMessage.post(new Uint8Array(111));

    }

}
```

Now it can be frustrating to have to store a private property only to call post on a object that we know is postable. Here is were this method come in handy:

```typescript
class Socket {

    readonly evtIsConnected= Evt.asNonPostable(Evt.create(false));
    readonly evtMessage= Evt.asNonPostable(Evt.create<Uint8Array>());

    constructor(){

        Evt.asPostable(this.evtIsConnected).state = true;
        Evt.asPostable(this.evtMessage).post(new Uint8Array(111));

    }


}
```


# Evt.asNonPostable(evt)

{% hint style="info" %}
Evt.asNonPostable() is the identity function with special type annotation
{% endhint %}

Return the passed evt typed as an object that can't be posted.

## Usecase:

Take [this example](https://docs.evt.land/api/statefulevt#make-a-statefulevt-readonly).

You could use this function to enforce that the return type by inferred and save you the trouble of having to import the `StatefulReadonlyEvt` interface:

```typescript
import { Evt } from "evt";

//Return an event that post every second.
function generateEvtTick(delay: number) {

    const evtTick= Evt.create(0);

    setInterval(()=> evtTick.state++, delay);

    retrun Evt.asNonPostable(evtTick);

}

const evtTick= generateTick(1000);


evtTick.state++; // TS ERROR
evtTick.post(2); // TS ERROR
```


# Evt.setDefaultMaxHandlers(n)

By default if an `Evt` is attached more than 25 handlers a warning will be displayed. It is possible to increase this limmit on a specific `Evt` instance using [`evt.setMaxHandlers(n)`](https://docs.evt.land/api/evt/setmaxhandlers) or globally with this static method.

Using this method will not overwrite the vale set on specific instance with `evt.setMaxHandlers(n)`.

Use Infinity or 0 to completely disable the warning.

{% hint style="warning" %}
Different version of EVT can be coabitating in a single project. The modification will only apply to the `Evt`s instantiated by this constructor.
{% endhint %}


# Ctx\<T>

`Ctx` helps detach all `Handler`s that were attached in the goal of acompishing a certain task once the said task is done or aborted.

{% hint style="info" %}
Get Ctx instance using[`Evt.newCtx<T>()`](https://docs.evt.land/api/evt/newctx) or [`Evt.getCtx(obj)`](https://docs.evt.land/api/evt/getctx)
{% endhint %}

{% hint style="info" %}
The only difference between `CtxVoid` and `Ctx<void>` is that `ctxVoid.done()` can be called without argument when `ctx<void>.done(result)`must be called with an argument (`null` or `undefined`).
{% endhint %}

## `ctx.done(result?)`

Detach, from the `Evt` instances they are attached to, all Handlers bound to the context.

{% hint style="info" %}
Once you have called ctx.done() the ctx can't be re-used. If you attach another handler using this ctx, it will be immediately detached. &#x20;
{% endhint %}

Calling this method causes the `Evt` returned by `ctx.getEvtDone()` to be posted.

{% hint style="info" %}
To test if ctx.done() have been invoked already you can use:`ctx.getEvtDone().postCount !== 0`
{% endhint %}

### Returns

`ReturnType<ctx.getHandlers()>` All the [Handler](https://docs.ts-evt.dev/api/handler)s that were bound to the context. They are now detached, calling `ctx.getHandler()` just after `ctx.done()` returns an empty array.

### Parameter

* `T` for `Ctx<T>`
* none for `VoidCtx`

## `ctx.abort(error)`

Equivalent of `ctx.done()` to use when the task did not go through.

{% hint style="info" %}
When a fλ operator returns `{ "DETACH": ctx, "err": error }`, `ctx.abort(error)` is invoked.
{% endhint %}

### Returns

`ReturnType<ctx.done()>` (cf `ctx.done` )

### Parameter

`Error` an error that describes what went wrong.

## `ctx.evtDoneOrAborted`

Tracks when ctx.done or ctx.abort are invoked.

{% hint style="info" %}
For most use cases, it is more convenient to use `ctx.waitFor([timeout])`
{% endhint %}

### Returns

* For VoidCtx an Evt that posts:
  * `{ handlers: Handler.WithEvt[] }` when `ctx.done()` is called.
  * `{ error: Error, handlers: Handler.WithEvt[] }` when `ctx.abort(error)` is called.
* For `Ctx<T>`, an `Evt` that post:
  * `{ result: Result; handlers: Handler.WithEvt[]; }` when `ctx.done(result)` is called.
  * `{ error: Error, handlers: Handlers.WithEvt[]; }` when `ctx.abort(error)` is called.

`Handler.WithEvt<T>` is just a type alias for an object that wraps a handler and the `Evt` it is attached to: `{ handler: Handler<T, any>, evt: Evt<T> }`

### Example

```typescript
import { Evt } from "evt";
import { EventEmitter } from "events";

const ctx= Evt.newCtx();

const evtText = new Evt<string>();
const evtTime = new Evt<number>();

evtText.$attach(
    text=> [ text.length ],
    ctx, 
    count => console.log("1: " + count)
);

evtTime.waitFor(
    time => time < 0,
    ctx,
).then(time=> console.log("2: " +  time));

evtText
    .pipe(ctx)
    .pipe(text => [text.toUpperCase()])
    .attach(upperCaseText=> console.log("3: " + upperCaseText))
    ;

Evt.merge(ctx, [ evtText, evtTime ])
    .attach(textOrTime => console.log("4: " + textOrTime))
    ;

const ee= new EventEmitter();

Evt.from<string>(ctx, ee, "text")
    .attach(text=> console.log("5: " + text))
    ;


evtText.post("foo"); //Prints "1: 3" "3: FOO" "4: foo"
ee.emit("text", "bar"); //Prints "5: bar"

console.log(evtText.getHandlers().length); //Prints "3"
console.log(evtTime.getHandlers().length); //Prints "2"

console.log(ee.listenerCount("text")); //Print "1"

ctx.evtDoneOrAborted.attachOnce(
    ({handlers})=> {

        console.log(
            handlers.filter(({ evt })=> evt === evtText).length +
            " handlers detached from evtText"
        );

        console.log(
            handlers.filter(({ evt })=> evt === evtTime).length +
            " handlers detached from evtTime"
        );

        console.log(
            handlers.length + " handlers detached total"
        );

    }
);

//Prints:
//"3 handlers detached from evtText"
//"2 handlers detached from evtTime"
//"5 handlers detached total"
ctx.done();

console.log(evtText.getHandlers().length); //Prints "0"
console.log(evtTime.getHandlers().length); //Prints "0"
console.log(ee.listenerCount("text")); //Print "0"

evtText.post("foo"); //Prints nothing
ee.emit("text", "bar"); //Prints nothing
```

[**Run the example**](https://stackblitz.com/edit/evt-niwafz?embed=1\&file=index.ts\&hideExplorer=1)

## `ctx.waitFor([timeout])`

Tracks via a Promise that resolves when `ctx.done()` or `ctx.abort()` is invoked.

### Returns

`Promise<T>` (`T` is the type argument of `Ctx<T>` ) A promise that resolve when ctx.done(\[result]) is invoked.

If `ctx.abort(error)` is invoked before `ctx.done()` the promise rejects with `error`.

If timeout was specified the promise rejects if `ctx.done()` was not invoked within `timeout` milliseconds. If it happens `ctx.abort(timeoutError)` is internally invoked `timeoutError` being an instance of `EvtError.Timeout`.

### Parameter

`number` Optional, number of milliseconds before the promise reject if it hasn't fulfilled within this delay.

## `ctx.getHandlers()`

### Returns

`Handler.WithEvt[]` The [`Handler`](https://docs.ts-evt.dev/api/handler)s that are bound to the context alongside with the `Evt` instance each one is attached to. The Handlers that are bound to the context but no longer attached to an Evt are not listed ( they are usually freed from memory anyway as there should be nor reference left of them as soon as they are detached ).

### Example

```typescript
//NOTE: Equivalent to evt.detach(ctx);
ctx
    .getHandlers()
    .filter(({ evt }))=> evt === evtString)
    .forEach(({ handler })=> handler.detach())
    ;
```

## `ctx.evtAttach`

### Returns

`Evt<Handler.WithEvt<any>>` An Evt that posts every time a new handler bound to the context is attached.

```typescript
import { Evt } from "evt";

const evtText = new Evt<string>();

const ctx= Evt.newCtx();

ctx.evtAttach.attach(handler => console.log(handler.timeout));

const timeout = 43;

evtText.attach(timeout, ()=>{}); //Prints "43"
```

[**Run the example**](https://stackblitz.com/edit/evt-t17qsy?embed=1\&file=index.ts\&hideExplorer=1)

## `ctx.evtDetach`

Same as `ctx.getEvtAttach()` but post when handlers are detached. Note that a handler being detached does not mean that it has been explicitly detached. One-time handlers and handlers that have timed out are automatically detached.

## Comprehensive example

Let us consider a practical use case of `Ctx`. The task is to download a file, we know the size of the file to download, we have an `Evt<Uint8Array>` that emits chunks of data, we want to accumulate them until we reach the expected file size. Multiple things can go wrong during the download:

* The user can cancel the download.
* The download can take too long.
* Socket may disconnect .
* The socket may send more data than expected.

Our expected output is a `Promise<Uint8Array>` that resolves with the downloaded file or reject if anything went wrong.

This is a possible implementation using `Ctx<Uint8Array>`:

```typescript
import { Evt, VoidEvt } from "evt";

function downloadFile(
    { fileSize, evtChunk, evtBtnCancelClick, evtSocketError, timeout }: {
        fileSize: number;
        evtChunk: Evt<Uint8Array>;
        evtBtnCancelClick: VoidEvt;
        evtSocketError: Evt<Error>;
        timeout: number;
    }
): Promise<Uint8Array> {

    const ctxDl = Evt.newCtx<Uint8Array>();

    evtSocketError.attachOnce(
        ctxDl,
        error => ctxDl.abort(error)
    );

    evtBtnCancelClick.attachOnce(
        ctxDl,
        () => ctxDl.abort(new Error("Download canceled"))
    );

    evtChunk
        .pipe(ctxDl)
        .pipe([
            (chunk, { byteLength, chunks }) => [{
                "byteLength": byteLength + chunk.length,
                "chunks": [...chunks, chunk]
            }],
            {
                "byteLength": 0,
                "chunks": id<Uint8Array[]>([])
            }
        ])
        .pipe(({ byteLength }) => byteLength >= fileSize)
        .pipe(({ byteLength, chunks }) => byteLength !== fileSize ?
            { "DETACH": ctxDl, "err": new Error("File is larger than expected") } :
            [chunks]
        )
        .pipe(chunks => [concatTypedArray(chunks, fileSize)])
        .attach(rawFile => ctxDl.done(rawFile))
        ;

    return ctxDl.waitFor(timeout);

}
```

[**Run the example**](https://stackblitz.com/edit/evt-qpke6h?embed=1\&file=index.ts\&hideExplorer=1)

Whether the download is successful or not this use of `Ctx` enforce that there is no left over handlers on the `Evt` passed as input once the download attempt has completed.


# Operator\<T, U> (type)

Operators provide a way to transform events data before they are passed to the callback.

EVT Operators can be of three types:

* **Filter**: `(data: T)=> boolean`.

  Only the matched event data will be passed to the callback.
* **Type guard**: `<U extends T>(data: T)=> data is U`

  Functionally equivalent to filter but restrict the event data type.
* **fλ**

  Filter / transform

  * **Stateless fλ**: `<U>(data: T)=> [U] | null`  Map the input type T to an output type U.
  * **Stateful fλ**: `[ <U>(data: T, prev: U)=> [U] | null, U /*initial value*/ ]`

    Same, but with a memory of the previous data.

## Where to use operators

Operators functions can be used with:

* All the [`evt.attach*(...)`](https://docs.ts-evt.dev/api-doc/evt#evt-usd-attach-methods) methods. [They have to be prefixed with `$` when used with fλ](https://docs.ts-evt.dev/api/evt/evt.-usd-attach-...-methods#the-usd-prefix).
* The [`evt.waitFor(...)`](https://docs.ts-evt.dev/api-doc/evt#evt-waitfor)   method
* The [`evt.pipe(...)`](https://docs.ts-evt.dev/api-doc/evt#evt-pipe) method.

```typescript
type Circle = {
    color: string;
    radius: number;
};

// Operator that ignore all non blue circle and return the radius of all blue circles.
const blueRadius = (circle: Circle)=> circle.color !== "blue" ? null : [circle.radius];

const evtCircle = Evt.create<Circle>();

// Usage with attach, ($) because it's a fλ
evtCircle.$attach(
    blueRadius,
    radius => { /* ... */}
);

const radius= await evtCircle.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'.

```typescript
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!");
```

[**Run the example**](https://stackblitz.com/edit/evt-38z5nd?embed=1\&file=index.ts\&hideExplorer=1)

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](https://docs.evt.land/api/operator#operator-type-guard).

## Operator - Type guard

If you use a filter that is also a [type guard](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards), 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.

```typescript
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";
```

The `matchCircle` type guard can be used to attach a callback to an `Evt<Shape>` that will only be called against circles.

```typescript
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 });
```

The type of the Shape object is narrowed down to `Circle`\
![Screenshot 2020-02-08 at 19 17 46](https://user-images.githubusercontent.com/6702424/74090059-baab3e00-4aa7-11ea-9c75-97f1fb99666d.png)

[**Run the example**](https://stackblitz.com/edit/evt-nn29kf?embed=1\&file=index.ts\&hideExplorer=1)

## Operator - fλ

Anonymous functions to simultaneously filter, transform the data and control the event flow.

**fλ Returns**

The type of values that a fλ operator sole determine what it does:

* `null` If the event should be ignored and nothing passed to the callback.
* `[ U ]`  When the event should be handled, wrapped into the singleton is the value will be passed to the callback.

### **Stateless fλ**

Stateless fλ operator only takes the event data as arguments.

```typescript
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 });
```

### **Stateful fλ**

The result of the previously matched event is passed as argument to the operator.

```typescript
import { Evt } from "evt";

const evtText= Evt.create<string>();

evtText.$attach(
    [ 
        (str, prev)=> [`${prev} ${str}`], 
        "START: "  //<= seed
    ],
    sentence => console.log(sentence)
);

evtText.post("Hello"); //Prints "START: Hello"
evtText.post("World"); //Prints "START: Hello World"
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/ts-evt-demo-stateful-qs1nsh?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

## Side effect

If you want your operator to have side effect you should use the second argument of the operator function `registerSideEffect`: &#x20;

{% embed url="<https://stackblitz.com/edit/ts-evt-demo-stateful-nxiqdt?file=index.ts>" %}

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. &#x20;

This is why it's important to make sure the the sideEffect is executed only when there is an actuall event posted. &#x20;

## Generic operators

Some generic operators are provided in `"evt/operators"` such as `scan`, `throttleTime` or `to` but that's about it.

```typescript
//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";
```


# StatefulEvt\<T>

A `StatefulEvt` is an Evt stat keep a reference to the last value posted.

You can think of it as way to observe when a value is changed.

{% embed url="<https://stackblitz.com/edit/evt-playground-wsa3je?file=index.ts>" %}

{% hint style="info" %}
`When you attach to a` StatefulEvt `the callback is immediately called with the current value (except with` attachExtract `and` attachOnceExtract`).`
{% endhint %}

## `.state`

Property type: `T`

reading the property gives the last event data posted. Setting the property (`evt.state = data`) is equivalent to calling `.post(data)`.

```typescript
import { Evt } from "evt";

const evtCount = Evt.create(0); // Equivalent wit new StatefulEvt<number>(0)

evtCount.attach(console.log);

console.log(evtCount.state); //Pints "state: 0"

evtIsConnected.post(1); //Pints "1" 

console.log(evtCount.state); //Prints "1";

evtCount.state++; //Prints "2"

console.log(evtCount.state); //Pints "2";
```

## `.pipe(...)`

Same as [`evt.pipe(...)`](https://docs.evt.land/api/evt/pipe) but return a `StatefulEvt`. Be aware that the current state of the `StatefulEvt` must be matched by the operator ( if any ) when invoking `.pipe()`, elst an exception will be thrown.

```typescript
import { Evt } from "evt";

type Circle = { 
    color: "WHITE" | "RED";
    radius: number;
};

const evtSelectedCircle = Evt.create<Circle>({ "color": "RED", "radius": 3 });

const evtSelectedCricleColor = 
    evtSelectedCircle.pipe(circle=> [ cicle.color ]);

evtSelectedCircleColor.attach(console.log);
```

## Converting an `Evt` into a `StatefulEvt`

Basic example: &#x20;

```typescript
import { Evt } from "evt";

const evtSrc = Evt.create<string>();

const evtFoo = evtSrc.toStatefull("initial value");

console.log(evtFoo.state === "initial value");

evtStr.post("new value");

console.log(evtFoo.state === "new value");
```

Concrete example:

```typescript
import { Evt } from "evt";

// Evt that post whenever the window is resized window.addEventListener("resize", ...)
const evtResize = Evt.from(window, "resize");

// A statefulle evt with evtInnerWith state which is always the current value of
// window.innerSize.
const evtInnerWidth = evtResize
    .toStatefull() // convert into a statefull evt with initial value set to unefined
    .pipe(()=> [window.innerWidth]);

```

## onlyIfChanged operator

When using stetefull Evt is often usefull to have event posted only when the state value has changed. For that purpose you can pipe with the onlyIfChanged operator. &#x20;

{% embed url="<https://stackblitz.com/edit/evt-playground-rgyith?embed=1&file=index.ts>" %}

Concrete example: &#x20;

If we take the previous example: &#x20;

```typescript
import { Evt } from "evt";


const evtInnerWidth = Evt.from(window, "resize")
    .toStatefull() 
    .pipe(()=> [window.innerWidth]);
    
evtInnerWith.attach(innerWidth => {

    // This callback will be called whenever the screen is resized 
    // including if only if the height has changed because
    // window.addEventListener("resize", ()=> ... 
    // is the source event emitter.  

});
```

Now if we put the `onlyIfChanged` operator intor the mix: &#x20;

```typescript
import { Evt, onlyIfChanged } from "evt";

const evtInnerWidth = Evt.from(window, "resize")
    .toStatefull() 
    .pipe(()=> [window.innerWidth])
    // By default it compare object structure so { foo: 3 } is considered equal to 
    // an other object that would also be { foo: 3 }
    .pipe(onlyIfChanged());
    
evtInnerWith.attach(innerWidth => {

    // This callback will only be called whenever window.innerWidth
    // actually changes.  

});
```

## Merging multiple `StatefulEvt`s

```typescript
import { Evt } from "evt";

const evtIsBlue= Evt.create(false);
const evtIsBig= Evt.create(false);

const evtIsBigAndBlue = Evt.merge([
    evtIsBlue.evtChange,
    evtIsBig.evtChange
])
    .toStateful()
    .pipe(()=> [ evtIsBlue.state && evtIsBig.state ])
    ;

console.log(evtIsBigAndBlue.state); // Prints "false"

evtIsBlue.state= true;

console.log(evtIsBigAndBlue.state); // Prints "false"

evtIsBig.state= true;

console.log(evtIsBigAndBlue.state); // Prints "true"
```

\*\*\*\*[**Run the example**](https://stackblitz.com/edit/evt-22pavm?embed=1\&file=index.ts\&hideExplorer=1)\*\*\*\*

## Make a `StatefulEvt` readonly

To prevent a StatefulEvt to be posted by parts of the code that is not supposed to StatefulEvt can be exposed as `StatefulReadonlyEvt`.

```typescript
import { StatefulEvt, StatefulReadonlyEvt } from "evt";

//Return an event that post every second.
function generateEvtTick(delay: number): StatefulReadonlyEvt<number> {

    const evtTick= new StatefulEvt(0);

    setInterval(()=> evtTick.state++, delay);

    retrun evtTick;

}

const evtTick= generateTick(1000);


evtTick.state++; // TS ERROR
evtTick.post(2); // TS ERROR
```

## `.toStateless([ctx])`

Return a stateless copy of the `Evt.`

```typescript
import { Evt } from "evt";

const evtText= Evt.create("foo");

//x is Evt<string>
const x= evtText.toStateless();
```

`evt.toStateless()` is equivalent to `Evt.prototype.pipe.call(evt)`


# Helper types

## ToNonPostableEvt\<E>

{% hint style="info" %}
`NonPostableEvt<T>` and `StatefulReadonlyEvt<T>` are interfaces implemented respectively by the classes `Evt<T>` and `StatefulEvt<T>`. They contains all the methods but the ones used to post events, namely: `.post(), .postOnceHandled()` and the `.state` setter for `StatefulReadonlyEvt`
{% endhint %}

```typescript
import { ToNonPostableEvt } from "evt";

ToNonPostableEvt<Evt<T>>         → NonPostableEvt<T>
ToNonPostableEvt<SatefulEvt<T>>  → StatefulReadonlyEvt<T>
ToNonPostable<VoidEvt>           → NonPostable<Void>
ToNonPostable<NonpostableEvt<T>> → NonPostableEvt<T>

ToNonPostableEvt<{ 
    evtText: Evt<string>; 
    evtCount: StatefulEvt<number>; 
    type: "FOO" 
}> 
 → 
{ 
    evtText: NonPostableEvt<string>; 
    evtCount: StatefulNonpostableEvt<number>; 
    type: "FOO"
}
```

Example use of the `NonPostableEvt` interface:

```typescript
import { Evt, NonPostableEvt } from "evt";

const evtText= new Evt<string>();

//Api to expose.
export const api:{ evtText: NonPostableEvt<string>; } = { evtText };

//evtText exposed by the api cannot be posted…
api.evtText.post //<=== TS error 
api.evtText.postOnceMatched //<===== TS error

//…but we can post internally.
evtText.post("good");
```

[**Run the example**](https://stackblitz.com/edit/evt-xc2eqj?embed=1\&file=index.ts\&hideExplorer=1)

## **ToPostableEvt\<E>**

Invert of `ToNonPostableEvt`

```typescript
import { 
    ToPostableEvt, 
    NonPostableEvt, 
    StatefulReadonlyEvt
} from "evt";

ToPostableEvt<NonPostableEvt<T>>         → Evt<T>
ToPostableEvt<StatefulReadonlyEvt<T>>    → StatefulEvt<T>
ToPostable<NonPostable<void>>            → VoidEvt
ToPostable<Evt<T>>                       → Evt<T>

ToPostableEvt<{ 
    evtText: NonPostableEvt<string>; 
    evtCount: StatefulReadonlyEvt<number>; 
    type: "FOO" 
}> 
 → 
{ 
    evtText: Evt<string>; 
    evtCount: StatefulEvt<number>; 
    type: "FOO"
}
```

## UnpackEvt\<E>

Extract the type argument of an Evt

```typescript
import { UnpackEvt } from "evt";

UnpackEvt<Evt<number>>            → number
UnpackEvt<StatefulEvt<number>>    → number
UnpackEvt<NonpostableEvt<number>> → number

UnpackEvt<{ 
    evtText: Evt<string>; 
    evtCount: StatefulEvt<number>; 
    type: "FOO" 
}> 
 → 
{ 
    evtText: string; 
    evtCount: number; 
    type: "FOO"
}
```

### Example:

UnpackEvt is a helper type to infer the type argument of an Evt instance.

```typescript
import { Evt, UnpackEvt } from "evt";

const evtHuman = new Evt<{
    name: string;
    age: number;
    gender: "MALE" | "FEMALE"
}>();


type Human = UnpackEvt<typeof evtHuman>;

const human: Human = {
    "name": "bob",
    "age": 89,
    "gender": "MALE"
};

evtHuman.post(human);
```

[**Run the example**](https://stackblitz.com/edit/evt-ykjacd?embed=1\&file=index.ts\&hideExplorer=1)

## SwapEvtType\<E, T>

```typescript
import { SwapEvtType } from "evt";

SwapEvtType<Evt<string>, number>          → Evt<number>
SwapEvtType<SatefulEvt<string>, number>   → SatefulEvt<number>
SwapEvtType<Evt<number>, void>            → VoidEvt
SwapEvtType<StatefulEvt<number>, void>    → VoidEvt
```

## FactorizeEvt\<E>

```typescript
import { FactorizeEvt } from "evt";

FactorizeEvt<Evt<string> | Evt<number>>     → Evt<string | number>
//...Work as well with StatefulEvt, NonPostable ect
```


# Handler\<T, U> (type)

Every time [`attach*`](https://docs.ts-evt.dev/api/evt/evt.attach), [`waitFor`](https://docs.evt.land/api/evt/waitfor) or [`pipe`](https://docs.evt.land/api/evt/pipe) is invoked a new [`Handler<T, U>`](https://docs.evt.land/api/handler) is attached to the [`Evt<T>`](https://docs.evt.land/api/evt).

Handlers can be listed using the [`evt.getHandler()`](https://docs.evt.land/api/evt/evt.gethandler) method.

```typescript
type Handler<T,U> = {

    //Method for detaching the handler from the Evt, returns false if 
    //if invoked when the handler is no longer attached.
    detach(): boolean;

    //The promise returned by the attach*() and waitFor() method.
    promise: Promise<U>;


    /* Properties that depends on the method used to attach the handler */

    //true if the handler was attached using a method containing "prepend"
    //in it's name. Example: evt.$attachOncePrepend(...)
    prepend: boolean;

    //... if the method contained "extract"
    extract: boolean;

    //... if the method contained "once"
    once: boolean;

    //if the method was waitFor()
    async: boolean;



    /* Properties passed as argument to the method used to attach the handler */

    //Default: ()=> true, a filter that matches all events.
    op: Operator<T,U>; 

    //Default: undefined
    ctx?: Ctx; 

    //Default: undefined.
    timeout?: number;

    //Undefined only when the handler was attached using evt.waitFor()
    callback?: (transformedData: U)=> void;

};
```

## Glossary relative to handers:

* An event is said to be **matched** by a handler if posting it causes the callback to be invoked. In practice this is the case when the handler's operator returns true or \[ value, ].
* An event is said to be **handled** by a handler if the event data is matched or if posting it causes the handler and/or other potential handlers to be detached. In practice this is the case when the handler's operator returns `"DETACH"` or `{DETACH: Ctx}.` It is possible to test if a given event data is handled by at least one of the handlers attached to an Evt\<T> by using the [`evt.isHandled(data)`](https://docs.ts-evt.dev/api/evt/evt.ishandled) method.


# React hooks

Evt let you work with events in react without having to worry about cleaning up afterward.

## useEvt()

{% embed url="<https://stackblitz.com/edit/evt-hooks-101?file=index.tsx>" %}
Basic example
{% endembed %}

{% embed url="<https://stackblitz.com/edit/react-ts-hqhuzk?file=App.tsx>" %}
Creating Evt from DOM Elements
{% endembed %}

The core idea is to always use the `ctx` to attach handlers. This will enable EVT to detach/reload handlers when they need to be namely when the component is unmounted or a value used in a handler has changed. &#x20;

## useRerenderOnStateChange()

{% embed url="<https://stackblitz.com/edit/react-ts-wquwqg?file=App.tsx>" %}
With StatefulEvt
{% endembed %}

## ESLint

You can use this [`react-hooks/exhaustive-deps`](https://github.com/facebook/react/blob/master/packages/eslint-plugin-react-hooks/README.md#advanced-configuration) to be warned if you forget a dependency:

```javascript
//package.json (if you use create-react-app otherwise use .eslintrc.js) 
{
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ],
    "rules": {
      "react-hooks/rules-of-hooks": "error",
      "react-hooks/exhaustive-deps": [
        "error",
        {
          "additionalHooks": "(useEvt)"
        }
      ]
    }
  }
}
```


# From EventEmitter to Evt

If you need to transition from EventEmitter to Evt without too much refactorying.

### All events in a single bus

In EventEmitter you had a single instance for many event types. In EVT, on the other hand, the recommended approach is to have an EVT for every event type.

That said, it's possible to use EVT just like EventEmitter.

```diff
-const EventEmitter = require("events");
+import { Evt, to } from "evt";

-const eeBus = new EventEmitter();
+const evtBus = new Evt<
+    | ["connect", void]
+    | ["disconnect", { cause: "remote" | "local" } ]
+    | ["error", Error]
+>();

-eeBus.on("disconnect", ({ cause })=> /* ... */);
+evtBus.attach(to("disconnect", ({ cause })=> /* ... */);

-eeBus.emit("disconnect", { cause: "remote" });
+evtBus.post([ "disconnect", { cause: "remote" }):

-eeBus.once("error", error => /* ... */);
+evtBus.attachOnce(to("error"), error => /* ... */);

-eeBus.removeAllListeners();
+evtBus.detach();

-const count = eeBus.listenerCount("disconnect");
+const count = evtBus.getHandlers()
+    .filter(handler => handler.op === to("disconnect"))
+    .length;

-eeBus.removeAllListeners("disconnect");
+evtText.getHandlers()
+    .filter(handler => handler.op === to("disconnect"))
+    .forEach(({ detach })=> detach());

const callback = ()=> { /* ... */ };

-eeBus.removeListener("connect", callback);
+evtText.getHandlers()
+    .filter(handler => handler.callback === callback)
+    .forEach(({detach})=> detach());

```

In EVT you can use `Ctx` to detach many handlers at once. It's much more convenient than using the callback ref.

```typescript
const ctx = Evt.newCtx();  

evtText.attach(to("connect"), ctx, ()=> { /* ... */ });
evtText.attach(to("disconnect"), ctx, error => { /* ... */ });

// Detach all handlers that have been attached using the ctx.
ctx.done();
```

### Extending/composing Evt

#### Inheritence (not recommended)

It is common practice to create classes that extends `EventEmitter` .&#x20;

As a general rule of thumb, we tend to avoid inheritance in favor of composition but if you want to do it there is how.

```typescript
import { Evt, to } from "evt";

class MySocket extends Evt<
    | ["connect", void]
    | ["disconnect", { cause: "remote" | "local" } ]
    | ["error", Error]
> {

    public readonly address: string;

    constructor(
        params: { 
            address: string; 
        }
    ) {

        super();

        const { address } = params;

        this.address = address;

        setTimeout(
            () => this.post(["connect", undefined]),
            300
        );

        setTimeout(
            () => this.post(["disconnect", { "cause": "local" }]),
            2000
        );

    }

}



const socket = new MySocket({ 
    "address": "wss://example.com"
});

(async ()=> {

  await socket.waitFor(to("connect"));

  console.log("Socket connected");

})();

socket.$attach(to("error"), error => { throw error });

socket.$attach(
    data=> data[0] === "disconnect" ? [ data[1] ] : null, //Just so you know this is what the to() operator do
    ({ cause })=> console.log(`socket disconnect (${cause})`)
);
```

[**Run the browser**](https://stackblitz.com/edit/evt-inheritence-pdzywu?file=index.ts)

#### Composition ( recommended approach )

Now we encourage favoring composition over inheritance and having one EVT instance for each events type. &#x20;

```typescript
import { Evt } from "evt";

class MySocket {

    public readonly address: string;
    
    /*
    We expose a NonPostableEvt copy of the Evt and not the Evt itself so we make 
    sure that the connect, disconnect and error events are not posted by the 
    user of the class and only internally.
    */
    #evtConnect = Evt.create();
    readonly evtConnect = Evt.asNonPostable(this.#evtConnect.pipe());
    
    #evtDisconnect = Evt.create<{ cause: "local" | "remote" }>();
    readonly evtDisconnect = Evt.asNonPostable(this.#evtDisconnect.pipe());
    
    #evtError = Evt.create<Error>();
    readonly evtError = Evt.asNonPostable(this.#evtError);

    constructor(
        params: { 
            address: string; 
        }
    ) {

        const { address } = params;

        this.address = address;


        setTimeout(
            () => this.#evtConnect.post(),
            300
        );

        setTimeout(
            () => this.#evtDisconnect.post({ "cause": "local" }),
            2000
        );

    }

}

const socket = new MySocket({ 
    "address": "wss://example.com"
});

(async ()=> {

  await socket.evtConnect.waitFor();

  console.log("socket connected");

})();

socket.evtError.attach(error => { throw error });

socket.evtDisconnect.attach(
    ({ cause }) => console.log(`socket disconnect (${cause})`)
);
```

[**Run in the browser**](https://stackblitz.com/edit/evt-inheritence-mnhwcs?file=index.ts)


# v1 -> v2

New features and breaking changes

{% hint style="success" %}
If you are only using the more commun features of `Evt` you can upgrade to v2 without facing any breaking change. &#x20;

Most of the breaking changes are related to [`StatefulEvt`](/api/statefulevt) and `React` integration.  &#x20;
{% endhint %}

{% hint style="warning" %}
Dropped backward compatibility with typescript 3.4.&#x20;

EVT now requires a version of TypeScript >= 3.8 (February 20th, 2020)
{% endhint %}

* [x] fλ Operators return type is `[U] | null (in v1: [U] | null | "DETACH" | {DETACH: Ctx} |...`&#x20;
* [x] `StatefulEvt`: When attaching the handler should immediately be triggered with the state value. (except with attachExtract, and other \*extract\* methods)
* [x] `StatefulEvt` evt.state= x only triggers evt.post(x) if x !== evt.state
* [x] Support DOM observable like [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) like `Evt.from(ctx, ResizeObserver, htmlElement).attach(...)`
* [x] `Ctx` All handler added with a `.done()` `Ctx` should are immediately detached.
* [x] Get read of `VoidEvt` and `VoidCtx` now that we can just use `Evt<void>` and `Ctx<void>`
* [x] Clean way for performing side effect in operators. [See example](https://stackblitz.com/edit/evt-playground-kisk2h?file=index.ts).
* [x] Easy way to test if an event data is handled by a particular operator `Evt.prototype.isHandledByOp()` (`Evt.prototype.getStatelesOp()` replaced by `Evt.prototype.getInvocableOp()`)
* [x] `evt/hooks/useStatefullEvt` renamed `useRerenderOnStateChange`
* [x] Export `evt/tools/typeSafety` into a separate module `tsafe`


