Files
socket.io/lib/parent-namespace.ts
Maxime Kjaer 0107510ba8 feat: add support for typed events (#3822)
Syntax:

```ts
interface ClientToServerEvents {
  "my-event": (a: number, b: string, c: number[]) => void;
}

interface ServerToClientEvents {
  hello: (message: string) => void;
}

const io = new Server<ClientToServerEvents, ServerToClientEvents>(httpServer);

io.emit("hello", "world");

io.on("connection", (socket) => {
  socket.on("my-event", (a, b, c) => {
    // ...
  });

  socket.emit("hello", "again");
});
```

The events are not typed by default (inferred as any), so this change
is backward compatible.

Note: we could also have reused the method here ([1]) to add types to
the EventEmitter, instead of creating a StrictEventEmitter class.

Related: https://github.com/socketio/socket.io/issues/3742

[1]: https://github.com/binier/tiny-typed-emitter
2021-03-10 00:18:13 +01:00

60 lines
1.6 KiB
TypeScript

import { Namespace } from "./namespace";
import type { Server } from "./index";
import type {
EventParams,
EventNames,
EventsMap,
DefaultEventsMap,
} from "./typed-events";
import type { BroadcastOptions } from "socket.io-adapter";
export class ParentNamespace<
ListenEvents extends EventsMap = DefaultEventsMap,
EmitEvents extends EventsMap = ListenEvents
> extends Namespace<ListenEvents, EmitEvents> {
private static count: number = 0;
private children: Set<Namespace<ListenEvents, EmitEvents>> = new Set();
constructor(server: Server<ListenEvents, EmitEvents>) {
super(server, "/_" + ParentNamespace.count++);
}
/**
* @private
*/
_initAdapter(): void {
const broadcast = (packet: any, opts: BroadcastOptions) => {
this.children.forEach((nsp) => {
nsp.adapter.broadcast(packet, opts);
});
};
// @ts-ignore FIXME is there a way to declare an inner class in TypeScript?
this.adapter = { broadcast };
}
public emit<Ev extends EventNames<EmitEvents>>(
ev: Ev,
...args: EventParams<EmitEvents, Ev>
): true {
this.children.forEach((nsp) => {
nsp.emit(ev, ...args);
});
return true;
}
createChild(name: string): Namespace<ListenEvents, EmitEvents> {
const namespace = new Namespace(this.server, name);
namespace._fns = this._fns.slice(0);
this.listeners("connect").forEach((listener) =>
namespace.on("connect", listener)
);
this.listeners("connection").forEach((listener) =>
namespace.on("connection", listener)
);
this.children.add(namespace);
this.server._nsps.set(name, namespace);
return namespace;
}
}