<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: mi-inu</title>
    <description>The latest articles on DEV Community by mi-inu (@yukimi-inu).</description>
    <link>https://dev.to/yukimi-inu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2926412%2F289f94d8-5207-455c-a696-7bf31262b3cb.png</url>
      <title>DEV Community: mi-inu</title>
      <link>https://dev.to/yukimi-inu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yukimi-inu"/>
    <language>en</language>
    <item>
      <title>If You Handle Enter, Check event.isComposing</title>
      <dc:creator>mi-inu</dc:creator>
      <pubDate>Tue, 30 Sep 2025 14:03:49 +0000</pubDate>
      <link>https://dev.to/yukimi-inu/why-16-billion-east-asians-are-quietly-raging-at-your-enter-key-handler-1po0</link>
      <guid>https://dev.to/yukimi-inu/why-16-billion-east-asians-are-quietly-raging-at-your-enter-key-handler-1po0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;TL;DR: Your Enter key handler is broken for 1.6 billion people using IME (Input Method Editor). When we press Enter to select a character during text conversion, your chat app sends a half-written message. Fix it with &lt;code&gt;event.isComposing&lt;/code&gt; check. Please. We're begging you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hey there, I'm Japanese.&lt;/p&gt;

&lt;p&gt;In Japan, we're basically taught from elementary school that suppressing anger and being polite is a virtue, so we develop this wonderful habit of bottling everything up until we absolutely explode. But today I've had a few drinks, so let me be honest with you.&lt;/p&gt;

&lt;p&gt;There's a reason almost every East Asian is pissed off at you ASCII-language developers.&lt;/p&gt;

&lt;p&gt;AI chat is all the rage these days, right? And when you think "chat," the normal UI is: press Enter in the text field, message sends. Simple. So you write something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;InputField&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleKeydown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onKeyDown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleKeydown&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah, that's it. Simple, clean, perfectly bug-free implementation. It passes your tests, passes E2E, passes QA, gets deployed. And then East Asians lose their minds completely.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;IME. Input Method Editor. Conversion. Composition. Whatever you want to call this nightmare.&lt;/p&gt;

&lt;p&gt;I'm Japanese, so let me explain Japanese. We use hiragana, katakana, and about 2,000 commonly-used kanji characters. Meanwhile, your typical keyboard has what, 104 keys?&lt;/p&gt;

&lt;p&gt;Obviously not enough. A-Z gives you 26 characters, but あ through ん alone is 46 characters. Why the hell do we use so many characters? Because Japanese people wanted to pack every ounce of emotion into their text. "Yoroshiku" (よろしく), "YOROSHIKU" (ヨロシク), "Yoroshiku" (宜しく), and "YO-RO-SHI-KU" (夜露死苦) all read as "yo-ro-shi-ku." よろしく is orthodox and friendly. ヨロシク means the person is either quirky or keeping their distance. 宜しく? That's a middle-aged salaryman. 夜露死苦? That's definitely a punk-fashion kid wreaking havoc on a huge motorcycle.&lt;/p&gt;

&lt;p&gt;Anyway, Japanese people care deeply about character representation even for the same sounds.&lt;/p&gt;

&lt;p&gt;So first, we type in ASCII to get phonetic hiragana, then we select from candidate characters that match those sounds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi0ycj620xa2k8zfahltu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi0ycj620xa2k8zfahltu.jpg" alt="Compositing: Yoroshiku" width="800" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This image shows exactly what's happening during composition. The underlined part is unconfirmed text, with candidates shown below. It even thoughtfully shows similar emoji and the meaning of each kanji character.&lt;/p&gt;

&lt;p&gt;To select the next candidate down, here's the key sequence visualized:&lt;/p&gt;

&lt;p&gt;y o r o s h i k u [Space] [Enter]&lt;/p&gt;

&lt;p&gt;During conversion, we use [Up] [Down] [Space] [Enter] [Esc] keys.&lt;br&gt;
This happens roughly every 1-3 words. Multiple times per minute of typing.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Nightmare in Action
&lt;/h2&gt;

&lt;p&gt;Now, let's look back at that first implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;InputField&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleKeydown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onKeyDown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleKeydown&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens when you implement this? Simple. The moment we try to select a character variant, the message sends.&lt;br&gt;
It's like sending "I " or "Describe this" or "Hi, I'm " in English.&lt;br&gt;
And since most chat apps reset the input field on send, our sentence never gets completed. So Japanese users quietly seethe with rage, open Sublime Text, and start typing there instead.&lt;/p&gt;

&lt;p&gt;This happens in SO MANY services originating from ASCII-land. I've sent bug reports and fixes to countless services, but it never ends. Claude Code's 9/30 update had this exact problem, and tons of Japanese users are pissed.&lt;/p&gt;

&lt;p&gt;Here's another fun example.&lt;br&gt;
Let's say you want to pick up input values and save them. Debounce the keydown event and save after xx ms. Simple, innocent logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;InputField&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onSave&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeoutRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleKeydown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;timeoutRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;onSave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onSave&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onKeyDown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleKeydown&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This doesn't cause problems by itself. But when upstream re-rendering happens and the element gets destroyed and recreated, absolute chaos ensues. Mid-conversion, the text suddenly disappears and reverts to an earlier state, or you get garbage hiragana stuck in the field. This actually happened in ChatGPT's macOS app.&lt;/p&gt;

&lt;p&gt;Writing is thought organization and output. These subtle harassment-level UX issues completely destroy a product's appeal.&lt;/p&gt;

&lt;p&gt;ASCII-language folks can't know this, can't notice this. That's why I'm writing this article today—we need to keep speaking up about this.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix That Will Save You From 1.6 Billion Enemies
&lt;/h2&gt;

&lt;p&gt;So how do we fix this? There's this incredibly convenient property called &lt;code&gt;event.isComposing&lt;/code&gt;.&lt;br&gt;
It tells you if conversion is happening right now. Simple bugs like saving mid-conversion can be prevented with this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;InputField&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onSave&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeoutRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleKeydown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isComposing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="nx"&gt;timeoutRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;onSave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onSave&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onKeyDown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleKeydown&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Safari Special Hell Edition
&lt;/h2&gt;

&lt;p&gt;But &lt;code&gt;isComposing&lt;/code&gt; has a huge problem: in Safari, it becomes false on the keydown event the moment Enter is pressed. This behavior has been ignored for ages, and if any Apple engineers are reading this, please create an issue immediately.&lt;/p&gt;

&lt;p&gt;Anyway, there's a proper way to work around this and a cheap trick. The easy one: during IME conversion, the keyCode for Enter becomes &lt;code&gt;229&lt;/code&gt; instead of &lt;code&gt;13&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;InputField&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleKeydown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isComposing&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keyCode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;229&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onKeyDown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleKeydown&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, more complex but modern approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;InputField&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isComposingRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleKeydown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isComposingRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleCompositionStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;isComposingRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleCompositionEnd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;isComposingRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; 
      &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
      &lt;span class="nx"&gt;onKeyDown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleKeydown&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onCompositionStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleCompositionStart&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onCompositionEnd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleCompositionEnd&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Please, For the Love of All That Is Holy
&lt;/h2&gt;

&lt;p&gt;That's it. That's literally it. This tiny bit of code prevents you from earning the hatred of 1.6 billion East Asians.&lt;/p&gt;

&lt;p&gt;Don't capture Enter, Esc, Up, or Down during isComposing. Just that. That's all it takes to save countless people from suffering.&lt;/p&gt;

&lt;p&gt;Oh, and by the way—Slack and Discord figured this out years ago. But somehow every new service steps on the exact same rake. Chinese developers with Pinyin input and Korean developers with Hangul composition are screaming alongside us.&lt;/p&gt;

&lt;p&gt;Go add this to your project's AGENTS.md right now: "When handling Enter in text fields, reference isComposing with Safari considerations." Better yet, add to your QA checklist: "When processing Enter, test with multi-byte character IME."&lt;/p&gt;

&lt;p&gt;This is all we East Asians wanted to say.&lt;br&gt;
I'm dead serious. Please.&lt;/p&gt;

&lt;p&gt;P.S. After reading this article, go buy coffee for the East Asian developer sitting next to you. They're probably silently patching your code as we speak.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>ux</category>
      <category>web</category>
    </item>
    <item>
      <title>Beyond EventEmitter: Introducing `mono-event` for Simpler, Stricter Event Management</title>
      <dc:creator>mi-inu</dc:creator>
      <pubDate>Sun, 30 Mar 2025 05:29:59 +0000</pubDate>
      <link>https://dev.to/yukimi-inu/beyond-eventemitter-introducing-mono-event-for-simpler-stricter-event-management-3gfh</link>
      <guid>https://dev.to/yukimi-inu/beyond-eventemitter-introducing-mono-event-for-simpler-stricter-event-management-3gfh</guid>
      <description>&lt;h2&gt;
  
  
  1. Introduction: The Event Handling Headache
&lt;/h2&gt;

&lt;p&gt;Ever found yourself wrestling with JavaScript or TypeScript event systems? Maybe you've been bitten by runtime errors because an event payload wasn't what you expected (&lt;code&gt;any&lt;/code&gt; strikes again!). Or perhaps you've spent too long debugging memory leaks caused by forgotten listeners. Traditional approaches like Node.js's &lt;code&gt;EventEmitter&lt;/code&gt; or DOM Events are powerful, but they often come with trade-offs: verbosity, potential type safety issues, and sometimes, performance bottlenecks.&lt;/p&gt;

&lt;p&gt;If these frustrations sound familiar, you're in the right place. Meet &lt;strong&gt;&lt;code&gt;mono-event&lt;/code&gt;&lt;/strong&gt;, a minimal, type-safe, single-event management library designed to bring clarity, safety, and impressive performance to your event handling code. Inspired by the simplicity of C# events, &lt;code&gt;mono-event&lt;/code&gt; focuses on doing one thing well: managing individual events with an intuitive API, strong typing, and excellent performance characteristics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Core Promise:&lt;/strong&gt; &lt;code&gt;mono-event&lt;/code&gt; delivers compile-time type safety, a minimal API, balanced performance, flexible listener management, and robust emission control, all in a tiny package.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Why We Need a Better Way: Problems with Existing Solutions
&lt;/h2&gt;

&lt;p&gt;While libraries like &lt;code&gt;EventEmitter3&lt;/code&gt; or native &lt;code&gt;EventTarget&lt;/code&gt; are widely used, they can introduce subtle challenges in modern TypeScript projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;any&lt;/code&gt; Trap:&lt;/strong&gt; Standard EventEmitters often rely on string-based event names and untyped payloads. This forces developers into defensive type checking or resorting to &lt;code&gt;any&lt;/code&gt;, sacrificing the benefits of TypeScript and opening the door to runtime errors.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Potential runtime error if 'data' is not a string&lt;/span&gt;
&lt;span class="nx"&gt;eventEmitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userLoggedIn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Welcome, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Oops! What if data is a number?&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Listener Management Complexity:&lt;/strong&gt; Manually managing &lt;code&gt;addListener&lt;/code&gt;/&lt;code&gt;removeListener&lt;/code&gt; or &lt;code&gt;on&lt;/code&gt;/&lt;code&gt;off&lt;/code&gt; can be verbose and error-prone. Forgetting to remove listeners is a common source of memory leaks, especially in dynamic applications or component lifecycles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Accidental Emissions:&lt;/strong&gt; When the &lt;code&gt;emit&lt;/code&gt; method is widely accessible, any part of the codebase can potentially trigger an event, sometimes unintentionally. This can make debugging complex interactions difficult and violate encapsulation principles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance Considerations:&lt;/strong&gt; While often fast enough, high-throughput scenarios or applications with frequent event emissions and listener changes can sometimes reveal performance bottlenecks in traditional event systems.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;mono-event&lt;/code&gt; was built specifically to address these pain points head-on.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Introducing &lt;code&gt;mono-event&lt;/code&gt;: Simple, Safe, and Fast
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;mono-event&lt;/code&gt; is built on a philosophy of minimalism, type safety, and balanced performance.&lt;/p&gt;

&lt;p&gt;A key design principle differentiating &lt;code&gt;mono-event&lt;/code&gt; is its &lt;strong&gt;"one event, one instance"&lt;/strong&gt; approach. Unlike traditional event emitters that manage multiple named events within a single instance (often leading to stringly-typed APIs and potential &lt;code&gt;any&lt;/code&gt; pitfalls), &lt;code&gt;mono-event&lt;/code&gt; requires you to create a distinct instance for &lt;em&gt;each specific type of event&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This instance itself carries the event's payload type information via generics (&lt;code&gt;mono&amp;lt;PayloadType&amp;gt;()&lt;/code&gt;). This fundamental design choice is what enables inherent compile-time type safety for both emitting and listening, eliminating a whole class of runtime errors common with string-based event systems. It also contributes to the library's minimal and focused API surface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Minimal API:&lt;/strong&gt; Easily add, remove, and emit events with just a few core functions (&lt;code&gt;add&lt;/code&gt;, &lt;code&gt;remove&lt;/code&gt;, &lt;code&gt;removeAll&lt;/code&gt;, &lt;code&gt;emit&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Compile-Time Type Safety:&lt;/strong&gt; Leverage TypeScript generics (&lt;code&gt;mono&amp;lt;PayloadType&amp;gt;()&lt;/code&gt;) to ensure event data types are checked at compile time, catching errors before they hit production.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mono&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mono-event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Declare the event payload type explicitly&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userLoginEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;userLoginEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 'payload' is correctly typed here!&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; logged in at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// console.log(payload.userName); // Compile-time error! Property 'userName' does not exist.&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;userLoginEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// userLoginEvent.emit({ userId: 'user-456' }); // Compile-time error! Missing 'timestamp'.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Balanced Performance:&lt;/strong&gt; Designed with a focus on balancing overall performance, memory usage, and bundle size, providing excellent results in practical use cases. (More on this in the Performance section!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tiny Bundle Size:&lt;/strong&gt; Only &lt;strong&gt;4.08 KB minified (1.05 KB gzipped)&lt;/strong&gt;, adding minimal overhead to your project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Synchronous / Asynchronous Support:&lt;/strong&gt; Choose between &lt;code&gt;mono&lt;/code&gt; (synchronous) and &lt;code&gt;monoAsync&lt;/code&gt; (asynchronous) versions. With &lt;code&gt;monoAsync&lt;/code&gt;, you can even control whether async listeners run sequentially (default) or in parallel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Emission Control Separation:&lt;/strong&gt; Use &lt;code&gt;monoRestrict&lt;/code&gt; and &lt;code&gt;monoRestrictAsync&lt;/code&gt; to separate the responsibilities of event registration (&lt;code&gt;add&lt;/code&gt;/&lt;code&gt;remove&lt;/code&gt;) and event emission (&lt;code&gt;emit&lt;/code&gt;). This is great for enforcing architectural patterns where only specific parts of your system should trigger an event.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flexible Listener Registration:&lt;/strong&gt; Register listeners simply, with a caller context (&lt;code&gt;this&lt;/code&gt;), or use the &lt;code&gt;{ once: true }&lt;/code&gt; option for one-time event handling. The &lt;code&gt;add&lt;/code&gt; method conveniently returns an &lt;code&gt;unsubscribe&lt;/code&gt; function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comprehensive Listener Management:&lt;/strong&gt; Remove listeners by reference, by caller context, or remove all listeners at once with &lt;code&gt;removeAll()&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Getting Hands-On: How to Use &lt;code&gt;mono-event&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Let's see &lt;code&gt;mono-event&lt;/code&gt; in action.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;mono-event

&lt;span class="c"&gt;# yarn&lt;/span&gt;
yarn add mono-event

&lt;span class="c"&gt;# bun&lt;/span&gt;
bun add mono-event

&lt;span class="c"&gt;# Deno (via npm specifier or esm.sh)&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; mono &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s2"&gt;"npm:mono-event"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
// or
import &lt;span class="o"&gt;{&lt;/span&gt; mono &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s2"&gt;"https://esm.sh/mono-event"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example 1: Basic Synchronous Events (&lt;code&gt;mono&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mono&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mono-event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create an event that carries a string payload&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messageEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// 1. Register a simple listener (returns an unsubscribe function)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unsubscribeSimple&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;messageEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Simple listener received:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Register a listener bound to a class instance (caller context)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;lastMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;handleEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Handler instance received:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;| Last:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MessageHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unsubscribeHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;messageEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 3. Register a one-time listener&lt;/span&gt;
&lt;span class="nx"&gt;messageEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;One-time listener received:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Emit the event&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Emitting 'Hello, Dev.to!'...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;messageEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, Dev.to!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// Simple listener received: Hello, Dev.to!&lt;/span&gt;
&lt;span class="c1"&gt;// Handler instance received: Hello, Dev.to! | Last: Hello, Dev.to!&lt;/span&gt;
&lt;span class="c1"&gt;// One-time listener received: Hello, Dev.to!&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Emitting 'Second Message'...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;messageEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Second Message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// Simple listener received: Second Message&lt;/span&gt;
&lt;span class="c1"&gt;// Handler instance received: Second Message | Last: Second Message&lt;/span&gt;
&lt;span class="c1"&gt;// (One-time listener does not fire again)&lt;/span&gt;

&lt;span class="c1"&gt;// Remove listeners&lt;/span&gt;
&lt;span class="nf"&gt;unsubscribeSimple&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Using the returned function&lt;/span&gt;
&lt;span class="nx"&gt;messageEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// By reference&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Emitting 'Third Message' (after removals)...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;messageEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Third Message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output: (No listeners left)&lt;/span&gt;

&lt;span class="c1"&gt;// Add some listeners back and remove all&lt;/span&gt;
&lt;span class="nx"&gt;messageEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Listener A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;messageEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Listener B&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;messageEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Emitting 'Fourth Message' (after removeAll)...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;messageEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fourth Message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output: (No listeners left)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example 2: Handling Asynchronicity (&lt;code&gt;monoAsync&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Need to perform async operations in your listeners? &lt;code&gt;monoAsync&lt;/code&gt; has you covered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;monoAsync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mono-event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;timers/promises&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Node.js example&lt;/span&gt;

&lt;span class="c1"&gt;// Event carrying a number payload&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processingEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;monoAsync&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Async listeners run sequentially by default&lt;/span&gt;

&lt;span class="c1"&gt;// Register async listeners&lt;/span&gt;
&lt;span class="nx"&gt;processingEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Async Listener 1: Starting processing &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Simulate async work&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Async Listener 1: Finished processing &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AsyncProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;processData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Async Processor: Starting work on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Async Processor: Done with &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AsyncProcessor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;processingEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;processData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Emit the event and wait for all sequential listeners to complete&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Emitting 42 (Sequential)...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;processingEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sequential emission complete.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output (order guaranteed):&lt;/span&gt;
&lt;span class="c1"&gt;// Async Listener 1: Starting processing 42...&lt;/span&gt;
&lt;span class="c1"&gt;// Async Listener 1: Finished processing 42.&lt;/span&gt;
&lt;span class="c1"&gt;// Async Processor: Starting work on 42...&lt;/span&gt;
&lt;span class="c1"&gt;// Async Processor: Done with 42.&lt;/span&gt;
&lt;span class="c1"&gt;// Sequential emission complete.&lt;/span&gt;

&lt;span class="c1"&gt;// Now, let's try parallel execution&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parallelEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;monoAsync&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;parallel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;parallelEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Parallel 1 (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;): Starting (500ms)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Parallel 1 (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;): Finished`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;parallelEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Parallel 2 (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;): Starting (300ms)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Parallel 2 (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;): Finished`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Emitting 'Task-A' (Parallel)...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;parallelEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Task-A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Parallel emission complete.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output (order depends on timing, but they run concurrently):&lt;/span&gt;
&lt;span class="c1"&gt;// Parallel 1 (Task-A): Starting (500ms)&lt;/span&gt;
&lt;span class="c1"&gt;// Parallel 2 (Task-A): Starting (300ms)&lt;/span&gt;
&lt;span class="c1"&gt;// Parallel 2 (Task-A): Finished&lt;/span&gt;
&lt;span class="c1"&gt;// Parallel 1 (Task-A): Finished&lt;/span&gt;
&lt;span class="c1"&gt;// Parallel emission complete.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example 3: Encapsulating Emission (&lt;code&gt;monoRestrict&lt;/code&gt; / &lt;code&gt;monoRestrictAsync&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Want to control &lt;em&gt;who&lt;/em&gt; can trigger an event? &lt;code&gt;monoRestrict&lt;/code&gt; separates the ability to add/remove listeners (&lt;code&gt;event&lt;/code&gt;) from the ability to trigger the event (&lt;code&gt;emit&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;monoRestrict&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mono-event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Imagine this is inside a class or module that manages state&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Create the restricted event&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;_onDataUpdate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;monoRestrict&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Expose only the 'event' part publicly for listeners&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;onDataUpdate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_onDataUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="c1"&gt;// Internal method that can emit the event&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Simulate fetching data&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apple&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;banana&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cherry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Data fetched, emitting update...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Only code with access to _onDataUpdate.emit can trigger it&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_onDataUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Public method to initiate the process&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;refreshData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// --- Code outside the DataService ---&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DataService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// External code can *only* add/remove listeners&lt;/span&gt;
&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onDataUpdate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;External Listener: Data updated!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Attempting to emit from outside fails (compile-time error in TS)&lt;/span&gt;
&lt;span class="c1"&gt;// service.onDataUpdate.emit(["fake data"]); // Error: Property 'emit' does not exist on type...&lt;/span&gt;

&lt;span class="c1"&gt;// Trigger the data fetch, which will internally emit the event&lt;/span&gt;
&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refreshData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// Data fetched, emitting update...&lt;/span&gt;
&lt;span class="c1"&gt;// External Listener: Data updated! [ 'apple', 'banana', 'cherry' ]&lt;/span&gt;

&lt;span class="c1"&gt;// The async version `monoRestrictAsync` works similarly.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example 4: Using Decorators (&lt;code&gt;monoDebounce&lt;/code&gt;, &lt;code&gt;monoThrottle&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;mono-event&lt;/code&gt; provides handy utilities for common patterns like debouncing and throttling event handlers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mono&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;monoDebounce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;monoThrottle&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mono-event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;timers/promises&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;waitMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Debounced: Executes only *after* 500ms of inactivity&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;debouncedHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;monoDebounce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[Debounced] Processing: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;waitMs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Throttled: Executes at most *once* every 500ms (leading + trailing edge)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;throttledHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;monoThrottle&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[Throttled] Handling: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;waitMs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;inputEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;debouncedHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;inputEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;throttledHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Simulating rapid input...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;inputEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Throttle runs immediately (leading edge)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;inputEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AB&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;inputEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ABC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Debounce timer resets&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Wait long enough for debounce &amp;amp; throttle trailing edge&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Input simulation finished.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Expected Output (approximate):&lt;/span&gt;
&lt;span class="c1"&gt;// Simulating rapid input...&lt;/span&gt;
&lt;span class="c1"&gt;// [Throttled] Handling: A&lt;/span&gt;
&lt;span class="c1"&gt;// (after ~600ms pause)&lt;/span&gt;
&lt;span class="c1"&gt;// [Debounced] Processing: ABC&lt;/span&gt;
&lt;span class="c1"&gt;// [Throttled] Handling: ABC  (trailing edge)&lt;/span&gt;
&lt;span class="c1"&gt;// Input simulation finished.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. API Overview
&lt;/h2&gt;

&lt;p&gt;Here's a quick reference for the main functions:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;mono&amp;lt;T&amp;gt;()&lt;/code&gt; (Synchronous)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Returns:&lt;/strong&gt; An object with methods:

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;add(handler: (args: T) =&amp;gt; void, options?: { once?: boolean }): () =&amp;gt; void&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;add(caller: object, handler: (args: T) =&amp;gt; void, options?: { once?: boolean }): () =&amp;gt; void&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;remove(handler: (args: T) =&amp;gt; void): boolean&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;remove(caller: object, handler: (args: T) =&amp;gt; void): boolean&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;removeAll(): void&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;emit(args: T): void&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;monoAsync&amp;lt;T&amp;gt;(options?: { parallel?: boolean })&lt;/code&gt; (Asynchronous)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Options:&lt;/strong&gt; &lt;code&gt;parallel&lt;/code&gt; (boolean, default &lt;code&gt;false&lt;/code&gt;): Run async listeners in parallel if &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Returns:&lt;/strong&gt; An object with methods similar to &lt;code&gt;mono&lt;/code&gt;, but handlers can be async (&lt;code&gt;(args: T) =&amp;gt; Promise&amp;lt;void&amp;gt; | void&lt;/code&gt;) and &lt;code&gt;emit(args: T): Promise&amp;lt;void&amp;gt;&lt;/code&gt; returns a Promise that resolves when all listeners complete.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;monoRestrict&amp;lt;T&amp;gt;()&lt;/code&gt; (Synchronous, Restricted Emission)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Returns:&lt;/strong&gt; &lt;code&gt;{ event, emit }&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;event&lt;/code&gt;: Object with &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;remove&lt;/code&gt;, &lt;code&gt;removeAll&lt;/code&gt; (like &lt;code&gt;mono&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;emit(args: T): void&lt;/code&gt;: A standalone function to trigger the event.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;monoRestrictAsync&amp;lt;T&amp;gt;(options?: { parallel?: boolean })&lt;/code&gt; (Asynchronous, Restricted Emission)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Returns:&lt;/strong&gt; &lt;code&gt;{ event, emit }&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;event&lt;/code&gt;: Object with &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;remove&lt;/code&gt;, &lt;code&gt;removeAll&lt;/code&gt; (like &lt;code&gt;monoAsync&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;emit(args: T): Promise&amp;lt;void&amp;gt;&lt;/code&gt;: A standalone async function to trigger the event.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Decorators
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;monoDebounce&amp;lt;F extends Function&amp;gt;(func: F, wait: number): F&lt;/code&gt;&lt;/strong&gt;: Creates a debounced version of &lt;code&gt;func&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;monoThrottle&amp;lt;F extends Function&amp;gt;(func: F, wait: number): F&lt;/code&gt;&lt;/strong&gt;: Creates a throttled version of &lt;code&gt;func&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Performance Deep Dive: The Numbers Don't Lie
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;mono-event&lt;/code&gt; is designed for a balance of speed, memory efficiency, and bundle size. Here's how it stacks up against popular alternatives based on recent benchmarks:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Benchmark environment: macOS, Apple M2 Ultra. Results are average of 3 runs. See &lt;a href="https://dev.todocs/performance"&gt;docs/performance&lt;/a&gt; in the repo for full details and methodology.)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance Summary (Node.js)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Init (ms)&lt;/th&gt;
&lt;th&gt;Register (Single) (ms)&lt;/th&gt;
&lt;th&gt;Register (Multi) (ms)&lt;/th&gt;
&lt;th&gt;Removal (Fwd) (ms)&lt;/th&gt;
&lt;th&gt;Removal (Bwd) (ms)&lt;/th&gt;
&lt;th&gt;Removal (Rnd) (ms)&lt;/th&gt;
&lt;th&gt;Emit (ms)&lt;/th&gt;
&lt;th&gt;Emit Once (ms)&lt;/th&gt;
&lt;th&gt;Memory (Empty) (KB/inst)&lt;/th&gt;
&lt;th&gt;Memory (100 Listeners) (KB/inst)&lt;/th&gt;
&lt;th&gt;Comprehensive (ms)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;mono-event&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5.76&lt;/td&gt;
&lt;td&gt;6.17&lt;/td&gt;
&lt;td&gt;6.04&lt;/td&gt;
&lt;td&gt;7.35&lt;/td&gt;
&lt;td&gt;75.13&lt;/td&gt;
&lt;td&gt;49.36&lt;/td&gt;
&lt;td&gt;205.42&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.12&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.13&lt;/td&gt;
&lt;td&gt;8.44&lt;/td&gt;
&lt;td&gt;1977.62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restrict&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;209.24&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EventEmitter3&lt;/td&gt;
&lt;td&gt;3.99&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.72&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.86&lt;/td&gt;
&lt;td&gt;218.14&lt;/td&gt;
&lt;td&gt;210.16&lt;/td&gt;
&lt;td&gt;238.02&lt;/td&gt;
&lt;td&gt;240.84&lt;/td&gt;
&lt;td&gt;224.64&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.09&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7.33&lt;/td&gt;
&lt;td&gt;1936.56&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mitt&lt;/td&gt;
&lt;td&gt;58.50&lt;/td&gt;
&lt;td&gt;3.85&lt;/td&gt;
&lt;td&gt;8.18&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6.09&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;10.68&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;9.01&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;217.67&lt;/td&gt;
&lt;td&gt;6.31&lt;/td&gt;
&lt;td&gt;0.49&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.94&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1999.64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nanoevents&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.84&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3.85&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.68&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;220.79&lt;/td&gt;
&lt;td&gt;172.63&lt;/td&gt;
&lt;td&gt;178.82&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;164.89&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;186.16&lt;/td&gt;
&lt;td&gt;0.23&lt;/td&gt;
&lt;td&gt;13.49&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1341.75&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RxJS&lt;/td&gt;
&lt;td&gt;4.44&lt;/td&gt;
&lt;td&gt;41.54&lt;/td&gt;
&lt;td&gt;79.27&lt;/td&gt;
&lt;td&gt;10.73&lt;/td&gt;
&lt;td&gt;12.67&lt;/td&gt;
&lt;td&gt;12.83&lt;/td&gt;
&lt;td&gt;372.83&lt;/td&gt;
&lt;td&gt;9.33&lt;/td&gt;
&lt;td&gt;0.15&lt;/td&gt;
&lt;td&gt;52.50&lt;/td&gt;
&lt;td&gt;5047.33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node Events&lt;/td&gt;
&lt;td&gt;101.13&lt;/td&gt;
&lt;td&gt;2.64&lt;/td&gt;
&lt;td&gt;30.17&lt;/td&gt;
&lt;td&gt;58.35&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.95&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;64.40&lt;/td&gt;
&lt;td&gt;237.65&lt;/td&gt;
&lt;td&gt;119.43&lt;/td&gt;
&lt;td&gt;0.28&lt;/td&gt;
&lt;td&gt;5.76&lt;/td&gt;
&lt;td&gt;1651.50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EventTarget&lt;/td&gt;
&lt;td&gt;164.45&lt;/td&gt;
&lt;td&gt;12229.94&lt;/td&gt;
&lt;td&gt;48.62&lt;/td&gt;
&lt;td&gt;156.30&lt;/td&gt;
&lt;td&gt;311.80&lt;/td&gt;
&lt;td&gt;262.19&lt;/td&gt;
&lt;td&gt;318.72&lt;/td&gt;
&lt;td&gt;339.96&lt;/td&gt;
&lt;td&gt;0.44&lt;/td&gt;
&lt;td&gt;9.34&lt;/td&gt;
&lt;td&gt;2735.08&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Performance Summary (Bun)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Init (ms)&lt;/th&gt;
&lt;th&gt;Register (Single) (ms)&lt;/th&gt;
&lt;th&gt;Register (Multi) (ms)&lt;/th&gt;
&lt;th&gt;Removal (Fwd) (ms)&lt;/th&gt;
&lt;th&gt;Removal (Bwd) (ms)&lt;/th&gt;
&lt;th&gt;Removal (Rnd) (ms)&lt;/th&gt;
&lt;th&gt;Emit (ms)&lt;/th&gt;
&lt;th&gt;Emit Once (ms)&lt;/th&gt;
&lt;th&gt;Comprehensive (ms)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;mono-event&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.38&lt;/td&gt;
&lt;td&gt;4.59&lt;/td&gt;
&lt;td&gt;12.91&lt;/td&gt;
&lt;td&gt;88.04&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.67&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;58.90&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;121.48&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.86&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;696.29&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restrict&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;126.51&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EventEmitter3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.98&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.43&lt;/td&gt;
&lt;td&gt;4.88&lt;/td&gt;
&lt;td&gt;178.34&lt;/td&gt;
&lt;td&gt;152.54&lt;/td&gt;
&lt;td&gt;195.17&lt;/td&gt;
&lt;td&gt;132.41&lt;/td&gt;
&lt;td&gt;160.25&lt;/td&gt;
&lt;td&gt;992.84&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mitt&lt;/td&gt;
&lt;td&gt;23.35&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.77&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.89&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6.35&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;9.94&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;9.64&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;180.11&lt;/td&gt;
&lt;td&gt;5.94&lt;/td&gt;
&lt;td&gt;2197.11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nanoevents&lt;/td&gt;
&lt;td&gt;2.20&lt;/td&gt;
&lt;td&gt;1.47&lt;/td&gt;
&lt;td&gt;2.91&lt;/td&gt;
&lt;td&gt;158.35&lt;/td&gt;
&lt;td&gt;152.67&lt;/td&gt;
&lt;td&gt;182.38&lt;/td&gt;
&lt;td&gt;136.22&lt;/td&gt;
&lt;td&gt;160.28&lt;/td&gt;
&lt;td&gt;1259.63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RxJS&lt;/td&gt;
&lt;td&gt;42.25&lt;/td&gt;
&lt;td&gt;12.16&lt;/td&gt;
&lt;td&gt;15.99&lt;/td&gt;
&lt;td&gt;7.36&lt;/td&gt;
&lt;td&gt;11.22&lt;/td&gt;
&lt;td&gt;11.83&lt;/td&gt;
&lt;td&gt;205.36&lt;/td&gt;
&lt;td&gt;6.57&lt;/td&gt;
&lt;td&gt;2005.92&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node Events&lt;/td&gt;
&lt;td&gt;118.95&lt;/td&gt;
&lt;td&gt;1.28&lt;/td&gt;
&lt;td&gt;4.19&lt;/td&gt;
&lt;td&gt;60.20&lt;/td&gt;
&lt;td&gt;0.91&lt;/td&gt;
&lt;td&gt;34.83&lt;/td&gt;
&lt;td&gt;145.26&lt;/td&gt;
&lt;td&gt;75.15&lt;/td&gt;
&lt;td&gt;989.63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EventTarget&lt;/td&gt;
&lt;td&gt;566.28&lt;/td&gt;
&lt;td&gt;13155.77&lt;/td&gt;
&lt;td&gt;34.42&lt;/td&gt;
&lt;td&gt;127.79&lt;/td&gt;
&lt;td&gt;252.76&lt;/td&gt;
&lt;td&gt;204.71&lt;/td&gt;
&lt;td&gt;1164.29&lt;/td&gt;
&lt;td&gt;132.11&lt;/td&gt;
&lt;td&gt;12307.24&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Memory Usage Summary (Node.js)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Per Instance (KB)&lt;/th&gt;
&lt;th&gt;With 10,000 Handlers (KB)&lt;/th&gt;
&lt;th&gt;1,000 Events × 100 Instances (KB)&lt;/th&gt;
&lt;th&gt;1,000,000 Instances (Total KB)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;mono-event&lt;/td&gt;
&lt;td&gt;0.09&lt;/td&gt;
&lt;td&gt;1,786.47&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;282,977.47&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EventEmitter3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.09&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;733.39&lt;/td&gt;
&lt;td&gt;5,366.01&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;166,269.33&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mitt&lt;/td&gt;
&lt;td&gt;0.31&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;260.34&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2,366.6&lt;/td&gt;
&lt;td&gt;527,172.73&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nanoevents&lt;/td&gt;
&lt;td&gt;0.24&lt;/td&gt;
&lt;td&gt;1,338.14&lt;/td&gt;
&lt;td&gt;19,156.15&lt;/td&gt;
&lt;td&gt;405,540.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RxJS&lt;/td&gt;
&lt;td&gt;0.13&lt;/td&gt;
&lt;td&gt;6,658.26&lt;/td&gt;
&lt;td&gt;73,713.15&lt;/td&gt;
&lt;td&gt;767,824.14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node Events&lt;/td&gt;
&lt;td&gt;0.12&lt;/td&gt;
&lt;td&gt;277.9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;91.51&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;249,870.11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EventTarget&lt;/td&gt;
&lt;td&gt;0.27&lt;/td&gt;
&lt;td&gt;1,046.12&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;537,181.27&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Analysis: How &lt;code&gt;mono-event&lt;/code&gt; Achieves its Speed (and Trade-offs)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Optimized Internals:&lt;/strong&gt; &lt;code&gt;mono-event&lt;/code&gt; uses simple JavaScript &lt;strong&gt;Arrays&lt;/strong&gt; to store listeners (&lt;code&gt;{ h: handler, c: caller }&lt;/code&gt; objects). Operations like &lt;code&gt;add&lt;/code&gt; (&lt;code&gt;push&lt;/code&gt;), &lt;code&gt;remove&lt;/code&gt; (&lt;code&gt;splice&lt;/code&gt; after a linear search), and &lt;code&gt;emit&lt;/code&gt; (iterating over array copies) are highly optimized by modern JavaScript engines.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Efficient &lt;code&gt;once&lt;/code&gt; Handling:&lt;/strong&gt; One-time listeners (&lt;code&gt;{ once: true }&lt;/code&gt;) are managed in a dedicated internal array (&lt;code&gt;onceListeners&lt;/code&gt;). When &lt;code&gt;emit&lt;/code&gt; occurs, these listeners are executed and then &lt;strong&gt;efficiently removed to prevent subsequent calls&lt;/strong&gt;. (Internally, this involves &lt;code&gt;splice&lt;/code&gt; for synchronous/sequential async modes, and array copying followed by clearing (&lt;code&gt;length = 0&lt;/code&gt;) for parallel async mode). This optimization ensures safe and fast handling of &lt;code&gt;once&lt;/code&gt; listeners, contributing significantly to the performance gains seen in &lt;code&gt;Emit Once&lt;/code&gt; benchmarks, especially in parallel async scenarios.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Prototype Sharing:&lt;/strong&gt; Methods like &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;remove&lt;/code&gt;, etc., are shared via prototype objects (&lt;code&gt;Object.create()&lt;/code&gt;), reducing the memory footprint and initialization cost for each event instance.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Memory vs. Speed:&lt;/strong&gt; Storing listeners in simple arrays means memory usage generally scales linearly with the number of listeners. While often acceptable, this can lead to higher memory consumption compared to libraries using more complex internal structures (like Maps per event name) when dealing with a very large number of listeners per instance. This is an &lt;strong&gt;intentional trade-off&lt;/strong&gt; favoring the speed of operations like &lt;code&gt;Emit Once&lt;/code&gt; and &lt;code&gt;remove&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When Does &lt;code&gt;mono-event&lt;/code&gt; Excel?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  High-frequency event emissions.&lt;/li&gt;
&lt;li&gt;  Heavy use of one-time (&lt;code&gt;once&lt;/code&gt;) listeners.&lt;/li&gt;
&lt;li&gt;  Scenarios where listener removal performance is critical.&lt;/li&gt;
&lt;li&gt;  Applications where compile-time type safety is paramount.&lt;/li&gt;
&lt;li&gt;  Architectures benefiting from clear separation of emission control (&lt;code&gt;monoRestrict&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Reproducibility:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can run the benchmarks yourself! Clone the repository, install dev dependencies, build, and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In the mono-event project directory&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;eventemitter3 mitt nanoevents rxjs &lt;span class="nt"&gt;--save-dev&lt;/span&gt; &lt;span class="c"&gt;# Install benchmark deps&lt;/span&gt;
npm run build

&lt;span class="c"&gt;# Run with Node.js (all tests)&lt;/span&gt;
node &lt;span class="nt"&gt;--expose-gc&lt;/span&gt; docs/performance/benchmark.js
&lt;span class="c"&gt;# Run specific tests (e.g., Emit and Comprehensive)&lt;/span&gt;
node &lt;span class="nt"&gt;--expose-gc&lt;/span&gt; docs/performance/benchmark.js 7 11

&lt;span class="c"&gt;# Run with Bun (Memory results may vary)&lt;/span&gt;
bun &lt;span class="nt"&gt;--gc-expose&lt;/span&gt; docs/performance/benchmark.js

&lt;span class="c"&gt;# Run with Deno (Memory results may vary)&lt;/span&gt;
deno run &lt;span class="nt"&gt;--import-map&lt;/span&gt; deno.importmap.json &lt;span class="nt"&gt;--allow-net&lt;/span&gt; &lt;span class="nt"&gt;--allow-read&lt;/span&gt; &lt;span class="nt"&gt;--allow-env&lt;/span&gt; docs/performance/benchmark.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Use Cases &amp;amp; Considerations
&lt;/h2&gt;

&lt;p&gt;So, when should you reach for &lt;code&gt;mono-event&lt;/code&gt;? It shines in scenarios where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Type Safety is Paramount:&lt;/strong&gt; If you're tired of &lt;code&gt;any&lt;/code&gt; and want compile-time guarantees for your event payloads in TypeScript.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Simplicity is Key:&lt;/strong&gt; You need basic, reliable event subscription and emission without the complexity of reactive streams (like RxJS).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Controlled Emission is Desired:&lt;/strong&gt; You want to enforce clear architectural boundaries using &lt;code&gt;monoRestrict&lt;/code&gt; to control &lt;em&gt;who&lt;/em&gt; can trigger events.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;once&lt;/code&gt; Listeners are Frequent:&lt;/strong&gt; The optimized handling of one-time listeners offers performance benefits.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Debounce/Throttle Utilities are Handy:&lt;/strong&gt; You need quick access to these common patterns for UI events or other frequent triggers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More specifically, &lt;code&gt;mono-event&lt;/code&gt; is a great fit for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;UI Components/Frameworks:&lt;/strong&gt; Managing internal state changes or user interactions within components.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;State Management:&lt;/strong&gt; Signaling updates between different parts of your application state.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Game Development:&lt;/strong&gt; Handling game events like collisions, player actions, or state transitions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Performance-Sensitive Systems:&lt;/strong&gt; Anywhere event emission speed or efficient &lt;code&gt;once&lt;/code&gt; listeners are crucial.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Modular Architectures:&lt;/strong&gt; Using &lt;code&gt;monoRestrict&lt;/code&gt; to enforce clear boundaries for event emission.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Any TypeScript project&lt;/strong&gt; where you want robust, type-safe event handling without unnecessary complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, &lt;code&gt;mono-event&lt;/code&gt; might &lt;em&gt;not&lt;/em&gt; be the best choice if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  You need complex event stream manipulation (filtering, mapping, combining streams) - RxJS is likely a better fit.&lt;/li&gt;
&lt;li&gt;  Absolute minimal bundle size is the &lt;em&gt;single most important&lt;/em&gt; factor (though &lt;code&gt;mono-event&lt;/code&gt; is already very small, &lt;code&gt;mitt&lt;/code&gt; or &lt;code&gt;nanoevents&lt;/code&gt; are slightly smaller).&lt;/li&gt;
&lt;li&gt;  You heavily rely on wildcard event listeners or need introspection capabilities not provided by the minimal API.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Conclusion &amp;amp; Call to Action
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;mono-event&lt;/code&gt; offers a compelling blend of &lt;strong&gt;type safety, performance, simplicity, and control&lt;/strong&gt; for event management in modern JavaScript and TypeScript applications. By addressing common pain points of traditional event emitters and focusing on a minimal, well-typed API, it helps you write more robust, maintainable, and performant code.&lt;/p&gt;

&lt;p&gt;Ready to give it a try?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;mono-event
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We welcome your feedback, bug reports, and contributions! Check out the project on GitHub:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/yukimi-inu/mono-event" rel="noopener noreferrer"&gt;https://github.com/yukimi-inu/mono-event&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Contributing Guidelines:&lt;/strong&gt; &lt;a href="https://github.com/yukimi-inu/mono-event/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Detailed Performance Docs:&lt;/strong&gt; &lt;a href="https://github.com/yukimi-inu/mono-event/tree/main/docs/performance" rel="noopener noreferrer"&gt;docs/performance&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let us know what you think in the comments below! Happy coding!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
