mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-27 06:43:19 +08:00
Bridge events whose typed listeners take no parameters
An event that typed code only listened to with a listener taking no parameters had no bridge entry: the scan marked a listener as typed only when one of its parameters was not a checked-dynamic value. Emitting the event through an `any` reference then threw instead of calling the listener. A TypeScript listener with no parameters now marks the event as typed. A JavaScript function without parameters still registers as before, since it can read `arguments`.
This commit is contained in:
@@ -338,9 +338,15 @@ function emitterEvents(lowerer: Lowerer): Map<string, EventSig> {
|
||||
const cbCt = lowerer.typeOf(node.arguments.nodes[1]);
|
||||
const cbT =
|
||||
lowerer.mapTypeOf(cbCt) ?? dynFallbackType(lowerer, node.arguments.nodes[1], cbCt);
|
||||
// A TypeScript listener with no parameters is typed too: it
|
||||
// registers without the adapter, so an untyped emit reaches it
|
||||
// only through the event's fixed ABI. A JavaScript function
|
||||
// without parameters can still read `arguments`.
|
||||
if (
|
||||
cbT?.kind !== "dyn" &&
|
||||
(cbT?.kind !== "func" || cbT.params.some((p) => p.kind !== "dyn"))
|
||||
(cbT?.kind !== "func" ||
|
||||
(cbT.params.length === 0 && !isJsSourceFile(sf)) ||
|
||||
cbT.params.some((p) => p.kind !== "dyn"))
|
||||
) {
|
||||
sigOf(name).typedListener = true;
|
||||
}
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/6941-emitter-untyped-zero-arg-listener.ts"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Emitting through an `any` reference reaches listeners that typed code
|
||||
// registered with no parameters, for an event no typed code emits: they
|
||||
// run once per emit, whatever arguments the untyped emit passes.
|
||||
|
||||
import { EventEmitter } from "node:events";
|
||||
|
||||
const emitter = new EventEmitter();
|
||||
let ready = 0;
|
||||
emitter.on("ready", () => {
|
||||
ready++;
|
||||
console.log("ready", ready);
|
||||
});
|
||||
emitter.once("closed", function () {
|
||||
console.log("closed once");
|
||||
});
|
||||
|
||||
const loose: any = emitter;
|
||||
console.log(loose.emit("ready"));
|
||||
console.log(loose.emit("ready", 1, "two"));
|
||||
console.log(loose.emit("closed", { reason: "done" }));
|
||||
console.log(loose.emit("closed"));
|
||||
console.log(loose.emit("missing"));
|
||||
console.log(emitter.listenerCount("ready"), emitter.listenerCount("closed"), ready);
|
||||
@@ -0,0 +1 @@
|
||||
{ "plain": 2800, "san": 3400 }
|
||||
Reference in New Issue
Block a user