mirror of
https://github.com/socketio/socket.io.git
synced 2026-04-30 03:00:39 -04:00
fix(sio): allow emitWithAck() for events with void callbacks (#5453)
EventNamesWithAck previously excluded events whose callback had no non-error arguments (e.g. `(cb: () => void) => void` or `(cb: (err: Error) => void) => void`). This made it impossible to use emitWithAck as a simple acknowledgement mechanism without data. The fix removes the FirstNonErrorArg void check while keeping the guard against events with no parameters at all, so events like `() => void` (no callback) are still correctly excluded. Related: https://github.com/socketio/socket.io/issues/5257
This commit is contained in:
@@ -22,8 +22,6 @@ export type EventNames<Map extends EventsMap> = keyof Map & (string | symbol);
|
||||
|
||||
/**
|
||||
* Returns a union type containing all the keys of an event map that have an acknowledgement callback.
|
||||
*
|
||||
* That also have *some* data coming in.
|
||||
*/
|
||||
export type EventNamesWithAck<
|
||||
Map extends EventsMap,
|
||||
@@ -32,11 +30,11 @@ export type EventNamesWithAck<
|
||||
Last<Parameters<Map[K]>> | Map[K],
|
||||
K,
|
||||
K extends (
|
||||
Last<Parameters<Map[K]>> extends (...args: any[]) => any
|
||||
? FirstNonErrorArg<Last<Parameters<Map[K]>>> extends void
|
||||
? never
|
||||
: K
|
||||
: never
|
||||
Parameters<Map[K]> extends never[]
|
||||
? never
|
||||
: Last<Parameters<Map[K]>> extends (...args: any[]) => any
|
||||
? K
|
||||
: never
|
||||
)
|
||||
? K
|
||||
: never
|
||||
|
||||
@@ -265,15 +265,11 @@ describe("server", () => {
|
||||
interface ServerToClientEventsWithMultipleWithAck {
|
||||
ackFromServer: (a: boolean, b: string) => Promise<boolean[]>;
|
||||
ackFromServerSingleArg: (a: boolean, b: string) => Promise<string[]>;
|
||||
// This should technically be `undefined[]`, but this doesn't work currently *only* with emitWithAck
|
||||
// you can use an empty callback with emit, but not emitWithAck
|
||||
onlyCallback: () => Promise<undefined>;
|
||||
}
|
||||
interface ServerToClientEventsWithAck {
|
||||
ackFromServer: (a: boolean, b: string) => Promise<boolean>;
|
||||
ackFromServerSingleArg: (a: boolean, b: string) => Promise<string>;
|
||||
// This doesn't work currently *only* with emitWithAck
|
||||
// you can use an empty callback with emit, but not emitWithAck
|
||||
onlyCallback: () => Promise<undefined>;
|
||||
}
|
||||
describe("Emitting Types", () => {
|
||||
@@ -420,8 +416,9 @@ describe("server", () => {
|
||||
sio.timeout(0).emitWithAck("noArgs");
|
||||
// @ts-expect-error - "helloFromServer" doesn't have a callback and is thus excluded
|
||||
sio.timeout(0).emitWithAck("helloFromServer");
|
||||
// @ts-expect-error - "onlyCallback" doesn't have a callback and is thus excluded
|
||||
sio.timeout(0).emitWithAck("onlyCallback");
|
||||
expectType<
|
||||
ToEmitWithAck<ServerToClientEventsWithMultipleWithAck, "onlyCallback">
|
||||
>(sio.timeout(0).emitWithAck<"onlyCallback">);
|
||||
expectType<
|
||||
ToEmitWithAck<
|
||||
ServerToClientEventsWithMultipleWithAck,
|
||||
@@ -496,10 +493,12 @@ describe("server", () => {
|
||||
s.emitWithAck("noArgs");
|
||||
// @ts-expect-error - "helloFromServer" doesn't have a callback and is thus excluded
|
||||
s.emitWithAck("helloFromServer");
|
||||
// @ts-expect-error - "onlyCallback" doesn't have a callback and is thus excluded
|
||||
s.emitWithAck("onlyCallback");
|
||||
// @ts-expect-error - "onlyCallback" doesn't have a callback and is thus excluded
|
||||
s.timeout(0).emitWithAck("onlyCallback");
|
||||
expectType<
|
||||
ToEmitWithAck<ServerToClientEventsWithAck, "onlyCallback">
|
||||
>(s.emitWithAck<"onlyCallback">);
|
||||
expectType<
|
||||
ToEmitWithAck<ServerToClientEventsWithAck, "onlyCallback">
|
||||
>(s.timeout(0).emitWithAck<"onlyCallback">);
|
||||
expectType<
|
||||
ToEmitWithAck<ServerToClientEventsWithAck, "ackFromServerSingleArg">
|
||||
>(s.emitWithAck<"ackFromServerSingleArg">);
|
||||
|
||||
Reference in New Issue
Block a user