-
Notifications
You must be signed in to change notification settings - Fork 10.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
send functions should have generic types #3742
Comments
I have a WIP implementation that would fix this issue on this branch. @darrachequesne would there be interest in potentially merging something like that? If so, I can complete the implementation. The implementation adds two optional type parameters to |
@MickL in the meantime, this library may be of interest to you: https://github.com/bterlson/strict-event-emitter-types (also see the blog post that explains the library). It allows you to cast socket.io types as strictly typed But this solution is not perfect; their implementation has a thing called |
@MaximeKjaer as long as the feature is stable and does not fail in surprising ways during compilation, that sounds interesting 😄 |
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: #3742 [1]: https://github.com/binier/tiny-typed-emitter
Syntax: ```ts interface ServerToClientEvents { "my-event": (a: number, b: string, c: number[]) => void; } interface ClientToServerEvents { hello: (message: string) => void; } const socket: Socket<ServerToClientEvents, ClientToServerEvents> = io(); socket.emit("hello", "world"); socket.on("my-event", (a, b, c) => { // ... }); ``` The events are not typed by default (inferred as any), so this change is backward compatible. Related: socketio/socket.io#3742
This was implemented by 0107510 (server) and socketio/socket.io-client@5902365 (client) and included in Socket.IO v4 🔥 Syntax: interface ClientToServerEvents {
noArg: () => void;
basicEmit: (a: number, b: string, c: number[]) => void;
}
interface ServerToClientEvents {
withAck: (d: string, cb: (e: number) => void) => void;
}
// client
import { io, Socket } from "socket.io-client";
const socket: Socket<ServerToClientEvents, ClientToServerEvents> = io();
// server
import { Server } from "socket.io";
const io = new Server<ClientToServerEvents, ServerToClientEvents>(3000); Documentation: https://socket.io/docs/v3/migrating-from-3-x-to-4-0/#Typed-events |
Not exactly what I desired but it should work. I wanted to do it per function instead of per server. |
@MickL if you want to only type certain events, you should be able to do: interface ServerToClientEvents {
withAck: (d: string, cb: (e: number) => void) => void;
[event: string]: (...args: any[]) => void;
} |
I meant more like this
Thats how most other libraries do it. |
You could always cast the But as far as I know, most type-safe event-emitter libraries actually take the same approach as what I implemented, i.e. an interface declaring all events and their types ahead of time. |
For example Angular http client does it like this: Or all NestJS Microservice Clients: I specifically used NestJS as the source of my proposal above. It is easy to implement two generics, it does not add any extra code and is totally optional to use. |
Syntax: ```ts interface ServerToClientEvents { "my-event": (a: number, b: string, c: number[]) => void; } interface ClientToServerEvents { hello: (message: string) => void; } const socket: Socket<ServerToClientEvents, ClientToServerEvents> = io(); socket.emit("hello", "world"); socket.on("my-event", (a, b, c) => { // ... }); ``` The events are not typed by default (inferred as any), so this change is backward compatible. Related: socketio/socket.io#3742
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: socketio#3742 [1]: https://github.com/binier/tiny-typed-emitter
Is your feature request related to a problem? Please describe.
Currently functions like emit are not typable:
This applies to both socket.io server and client.
Describe the solution you'd like
I would like to have generic types on all emit functions to (optionally) type the send-object and the response-object:
Now if an interface changes TypeScript throws an error if the objects are not updated.
Suggested solution
Functions could look something like this:
The text was updated successfully, but these errors were encountered: