Skip to content

Type issues with emit and emitWithAck #4813

Closed
@ZachHaber

Description

@ZachHaber

Describe the bug
When using emit, emitWithAck, and the server side variants, there are issues with the types of Broadcaster, Server, Namespace, and Socket types.

To Reproduce

Socket.IO server version: 4.7.2

Server

import { Server } from "socket.io";

export interface ServerToClientEvents {
  basicEmit: (a: number, b: string) => void;
  withAck: (d: string, callback: (e: number) => void) => void;
  // multiple Ack arguments doesn't work on broadcasts - single target
  withAck2: (d: string, callback: (e: number, f: string) => void) => void;
}
export interface ClientToServerEvents {}
const io = new Server<ClientToServerEvents,ServerToClientEvents>(3000, {});

//Emits
// no callback
io.timeout(1).emit('basicEmit',3,'')
// Likely should be a type error as it doesn't have a callback at all
// Currently just times out...

// One arg in callback
io.emit('withAck', 'hello', (...args) => { });
//=> ❌ typeof args === [number], should be [number[]]
io.timeout(1).emit('withAck', 'hello', (...args) => {});
//=> ✅ typeof args === [Error, number[]]
io.to('1').to('2').emit('withAck','',(...args)=>{})
//=> ❌ typeof args === [number], should be [number[]]

// Two args in callback
io.emit('withAck2', 'hello', (...args) => { });
//=> ❌ typeof args === [number,string], should be [number[]]
io.timeout(1).emit('withAck2','hello',(...args)=>{});
//=> ❌ typeof args === [Error,number,string], should be [Error,number[]]

// EmitWithAcks
// no callback
io.emitWithAck('basicEmit',3,'')
//=> type error: Expected 2 arguments, got 3 (the last argument is clipped off)
// Should just be a type-error, as without `timeout` applied, it will likely just never resolve
// if you apply a timeout, then it just times out eventually due to not having a callback

// One arg in callback
io.emitWithAck('withAck','hello');
//=>❌ type is Promise<any>, should be Promise<number[]>
io.timeout(1).emitWithAck('withAck','hello')
//=>✅ type is Promise<number[]>

// Two args in callback - doesn't even work in timeout broadcaster
io.emitWithAck('withAck2','hello');
//=>❌ type is Promise<any>, should be Promise<number[]>
io.timeout(1).emitWithAck('withAck2','hello')
//=>❌ type is Promise<any>, should be Promise<number[]>


io.on("connection", (socket) => {
  // emit is fine on the socket instance itself
  socket.broadcast.emit('withAck','hello',(...args)=>{});
  //=>❌ typeof args === [number], should be [number[]]
  socket.broadcast.timeout(1000).emit('withAck', 'hello',(...args)=>{});
  //=>✅ typeof args === [Error, number[]]
  // important to note that whatever types exist needs to work with socket.broadcast.timeout(1) AND socket.timeout(1).broadcast
  socket.timeout(1).broadcast.timeout(1).emit('withAck','hello',(...args)=>{});
  //=>❌ typeof args === [Error, Error, number[]], should be [Error, number[]]
  // Needs to not re-decorate the event if an error was already added. (not sure what benefit allowing this gives in the first place
  
  // emitWithAck is backwards here vs the broadcast based ones...
  socket.emitWithAck('withAck','hello');
  //=>✅ Promise<number>
  socket.timeout(1).emitWithAck('withAck','hello');
  //=>❌ Promise<any>, should be Promise<number>
  
  // two args
  socket.emitWithAck('withAck2','hello');
  //=>❌ Promise<any>, should be Promise<number>
  socket.timeout(1).emitWithAck('withAck2','hello');
  //=>❌ Promise<any>, should be Promise<number>
});

Socket.IO client version: x.y.z

Client
I haven't checked on the client, but I assume the same types are used on here too (to some extent)

Expected behavior
Type definitions should be consistent with what socket.io is doing so that we can fully rely on them. As of the moment, they are wrong in a few places that are either frustrating (any instead of a real type) or problematic (number instead of number[]).

Platform:

  • Typescript 5.2

Additional context
I have some first passes at solving some of these issues that I can work towards improving and turning into a PR, if that's desired.

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions