-
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
Use own interface for Socket request to allow extending the request interface independently of Express. #4787
base: main
Are you sure you want to change the base?
Conversation
… with custom properties without polluting the IncomingMessage type which is also used by Express/Passport Using socket.io with passport middlewares causes issues when using the same 'userProperty' key for both - by extending IncomingMessage { user: Express.user } we break passport's isAuthenticated() function which returns never in the else case since the IncomingMessage always has a user property on itself. To fix this, I believe we should be able to extend only the request type inside socket.io -> SocketRequest.
Hi @darrachequesne, sorry to bother you, would you please review this change. |
References #4795 |
The example is now available with different syntaxes: - CommonJS - ES modules - TypeScript Related: #4787
Hi! I'm not sure this is needed actually, you should be able to reuse the same import { type Request } from "express";
declare module "express-session" {
interface SessionData {
count: number;
}
}
io.on("connection", (socket) => {
const req = socket.request as Request;
req.session.count++;
}); I've updated the example here: https://socket.io/how-to/use-with-express-session |
Hi @darrachequesne , thanks for looking at this, but I don't think it solves the issue. You are hard-casting the request to be something it is not, an express Request.
whereas with the change suggested in this PR, we can extend the SocketRequest interface to include the fields we need - it is not the cleanest solution either, because we are still lying to TS, but in user code we don't need to cast the request everytime we want to use it. Probably the best solution would be to add a generic to the Socket for the type of Request class Socket<..., SocketRequest extends IncomingRequest = IncomingRequest> {
public get request(): SocketRequest { |
Hi, sorry to bother you @darrachequesne, I still think there is something to fix. Please see my comment above. |
Fair enough! That being said, with your solution one would need to declare the declare module "express-session" {
interface SessionData {
count: number;
}
}
declare global {
namespace Express {
interface User {
username: string;
}
}
}
const io = new Server<any, any, any, any, IncomingMessage & {
session: Session & {
count: number;
},
user: Express.User
}>(httpServer); |
Yes, but you can reuse the interface SocketRequest extends IncomingMessage {
session: Session & Partial<SessionData>
user: Express.User
}
const io = new Server<any, any, any, any, SocketRequest > |
@alesmenzel something like this then? |
@darrachequesne Yes, but I don´t understand using merging With custom "IncomingMessage", it should be possible to just return
without typecasting. |
If I understand correctly, you are suggesting something like this: export class Socket<
ListenEvents extends EventsMap = DefaultEventsMap,
EmitEvents extends EventsMap = ListenEvents,
ServerSideEvents extends EventsMap = DefaultEventsMap,
SocketData = any,
SocketRequest extends IncomingMessage = IncomingMessage
> extends StrictEventEmitter<
ListenEvents,
EmitEvents,
SocketReservedEventsMap
> {
// [...]
public get request(): SocketRequest {
return this.client.request;
}
} But in that case, TypeScript complains:
Or am I missing something? Could you please open a pull request with what you had in mind? |
The example is now available with different syntaxes: - CommonJS - ES modules - TypeScript Related: socketio/socket.io#4787
Use own interface for Socket request to allow extending the request interface with custom properties without polluting the IncomingMessage type which is also used by Express/Passport.
Using socket.io with passport middlewares causes issues when using the same 'userProperty' key is used for both - for example by extending
IncomingMessage { user: Express.User }
we break passport'sisAuthenticated()
function, because now typescript thinks that the request is always of the typeAuthenticatedRequest
asIncomingMessage
always has a user property on itself. To fix this, I believe we should be able to extend only the request type inside socket.io -> SocketRequest.The kind of change this PR does introduce