-
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
[typescript] share session data across express and socket.io #3890
Comments
I found a workaround for this issue which does not require any external library. ConfiguringConfigure the socket.io server like so: const session = ... // define your express session
const io = ... // define your socket.io server
const wrapper = (middleware: any) => (socket: Socket, next: any) => middleware(socket.request, {}, next);
io.use(wrapper(session)); I keep my TypeScript settings really tightened so I needed that wrapper function to make TypeScript shut up for once. io.use((socket: Socket, next: any) => session(socket.request, {}, next)); If it doesn't, just stick with the first option. The following needs to be added to types.ts; modify the names of the interfaces as you like, EXCEPT import type { IncomingMessage } from 'http';
import type { SessionData } from 'express-session';
import type { Socket } from 'socket.io';
declare module 'express-session' {
interface SessionData {
username: string
// ... the rest of the variables you intent to store in the session object
}
};
interface SessionIncomingMessage extends IncomingMessage {
session: SessionData
};
export interface SessionSocket extends Socket {
request: SessionIncomingMessage
}; Usageimport type { SessionSocket } from './types';
function doSomethingWithSocket(socket: SessionSocket) {
console.log('username is: ' + socket.request.session.username);
};
io.on('connection', (defaultSocket: Socket) => {
const socket = <SessionSocket> defaultSocket;
const username = socket.request.session.username; // retrieve any variable from the session
doSomethingWithSocket(socket);
}); |
Actually there is a simpler solution (maybe not cleaner depending on your point of view): declare module 'socket.io' {
interface Socket {
request: SessionIncomingMessage
}
} |
Did you test this? TypeScript doesn't seem to like it. I am still forced to use the method which I have shown above. Thanks for sharing anyways, maybe it'll help someone else! |
Damnit you're right ! I didn't test this because I wrote this from an example where I was not changing a property of Socket, but adding one, which declaration merging allows. However, in your case you are changing the type of an existing property on Socket, and declaration merging forbids this... |
OK just to say that there is a workaround in your case, but know that it is a little bit filthy... What you can do is augment the IncomingMessage interface from the http module: declare module 'node:http' {
interface IncomingMessage {
session: string
}
} Since socket.io uses that definition, you will have session on it. But also every type definition that uses IncomingMessage from the http module will have it, which is maybe not something you want, or maybe it is. |
There is one slight (or major) issue to my and probably your solution too. Any property which is updated using I cannot wrap my head around it and I really do not know what is the cause of it, nor how to fix it. @barroudjo do you have any idea on how to fix this or what could be the problem of it, so I can help to find a solution? |
What you're describing here is a JavaScript problem, not a typescript one. So the solution must lie in looking at how the session is implemented on the socket vs how it is implemented in express. Not my expertise, and I don't have the time to delve into this, sorry ! |
Did you find a solution to this? I am having the issue with typing when passing
That's not a big problem. The problem here is that the session object in |
Is there any progress? |
it seems both 3.X and 4.X versions have this issue, downgrade to 2.X everything goes smoothly. it is bypassed in another thread using a hack. |
Oh yes, you’re right! My bad, sorry for hijacking the ticket |
This is my solution:
Please read module augmentation as described |
For future readers: I've added an example in the documentation: https://socket.io/how-to/use-with-express-session#with-typescript Please reopen if needed. |
Hello, @darrachequesne , I have tried to follow that section of documentation and discovered that Node throws build error: My setup:
I have checked conflicted type declarations and noticed that @types/express-session extends Request type declaration like so (comments omitted):
After adding missing type intersection for
|
Describe the bug
I recently moved from JavaScript to TypeScript and I'm having a difficult time trying to share session data across express and socket.io.
To Reproduce
Socket.IO server version:
4.0.1
Server
main.ts:
types.ts, to expand (I doubt this is the appropriate word) the session object by augmenting the module:
The above allows me to use
req.session.username
inapp
callbacks.Expected behavior
I want to be able to access express session data from a
Socket
object.Platform:
Windows 10, Node v14.16.0, TypeScript v4.2.4
Additional context
In JS, this is what I used:
I tried two options to achieve the same in TS:
Property 'res' does not exist on type 'IncomingMessage'
, which I could fix by changingsocket.request.res || {}
to{}
. Not sure if it was mandatory or even needed as I can't test it.Argument of type 'IncomingMessage' is not assignable to parameter of type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'
, which I could not fix at all.No errors, until I try getting the value of
socket.handshake.session.username
(see docs for usage), which, of course, raises an error:Property 'session' does not exist on type 'Handshake'
.The text was updated successfully, but these errors were encountered: