-
Notifications
You must be signed in to change notification settings - Fork 33
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
fix types #18
fix types #18
Conversation
This looks very good to me. It fixes the problem described in #8 and also makes sense code-wise. I only have a few nitpicky remarks (see review below). |
xhrState: number; | ||
xhrStatus: number; | ||
} | ||
export type Events = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Errors of type 'timeout' are also emitted via the 'error' event. There is no dedicated 'timeout' event. So this type should be changed to:
export type Events = {
message: {
type: 'message';
data: string | null;
lastEventId: string | null;
url: string;
};
open: {
type: 'open';
};
close: {
type: 'close';
};
error: {
type: 'error';
message: string;
xhrState: number;
xhrStatus: number;
} | {
type: 'exception';
message: string;
error: Error;
} | {
type: 'timeout';
};
}
|
||
export type EventSourceListener<E extends string = never> = ( | ||
event: CustomEvent<E> | EventSourceEvent | ||
export type EventSourceListener<E extends EventType | string> = ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be useful if the EventSourceListener
type would also work without a type argument. This could easily be achieved by making E
default to EventType
like this:
export type EventSourceListener<E extends EventType | string = EventType> = (
@wojciechkrol I can assure you that this works perfectly. Are you using it like this? type MyCustomEvents = 'ping' | 'clientConnected' | 'clientDisconnected';
const es = new EventSource<MyCustomEvents>('https://your-sse-server.com/');
es.addEventListener('open', (event) => {
console.log('Open SSE connection:', event);
});
es.addEventListener('message', (event) => {
console.log('Received SSE message:', event);
});
es.addEventListener('error', (event) => {
console.log('SSE error:', event);
});
es.addEventListener('ping', (event) => {
console.log('Received ping:', event);
});
es.addEventListener('clientConnected', (event) => {
console.log('Client connected:', event);
});
es.addEventListener('clientDisconnected', (event) => {
console.log('Client disconnected:', event);
}); |
@EmilJunker I have a single listener handling multiple event types as shown: const listener: EventSourceListener<MyCustomEvents> = (event) => {
// ...
if (event.type === 'open') {
// ...
} else if (event.type === 'ping') {
// ...
}
// ...
}
es.addEventListener('open', listener);
es.addEventListener('ping', listener); These changes interfere with this approach. However, I've opened another PR that addresses these issues. Please take a moment to review it: #29. |
@wojciechkrol I'm not a big fan of the implementation in #29 It doesn't let me define an event handler function separately and then assign it like this: const myPingHandler: EventSourceListener<'ping'> = (e) => {
console.log(e.data); // error because property 'data' might not exist
};
es.addEventListener('ping', myPingHandler); Similarly, it doesn't let me define a handler that is just for my custom events like this: const myHandlerForCustomEvents: EventSourceListener<MyCustomEvents> = (e) => {
console.log(e.data); // error because property 'data' might not exist
};
es.addEventListener('ping', myHandlerForCustomEvents);
es.addEventListener('clientConnected', myHandlerForCustomEvents);
es.addEventListener('clientDisconnected', myHandlerForCustomEvents); The implementation by ingvardm lets me do all of these things. If you want to define one handler for everything, you can simply do it like this: const listener: EventSourceListener<MyCustomEvents | EventType> = (event) => {
// ...
if (event.type === 'open') {
// ...
} else if (event.type === 'ping') {
// ...
}
// ...
};
es.addEventListener('open', listener);
es.addEventListener('message', listener);
es.addEventListener('error', listener);
es.addEventListener('ping', listener);
es.addEventListener('clientConnected', listener);
es.addEventListener('clientDisconnected', listener); |
First and foremost, const myPingHandler: EventSourceListener<MyCustomEvents, 'ping'> = (e) => {
console.log(e.data);
};
es.addEventListener('ping', myPingHandler); and const myHandlerForCustomEvents: EventSourceListener<MyCustomEvents, MyCustomEvents> = (e) => {
console.log(e.data);
};
es.addEventListener('ping', myHandlerForCustomEvents);
es.addEventListener('clientConnected', myHandlerForCustomEvents);
es.addEventListener('clientDisconnected', myHandlerForCustomEvents); and const listener: EventSourceListener<MyCustomEvents> = (event) => {
// ...
if (event.type === 'open') {
// ...
} else if (event.type === 'ping') {
// ...
}
// ...
};
es.addEventListener('open', listener);
es.addEventListener('message', listener);
es.addEventListener('error', listener);
es.addEventListener('ping', listener);
es.addEventListener('clientConnected', listener);
es.addEventListener('clientDisconnected', listener); If you want an approach similar to what you currently have, feel free to create your own type: type CustomEventListener<T extends EventType<E>, E extends string = MyCustomEvents> = EventSourceListener<E, T>;
const myPingHandler: CustomEventListener<'ping'> = (e) => {
console.log(e.data);
};
es.addEventListener('ping', myPingHandler); Thanks to this, we have additional control over which events are handled by EventSourceListener (type hint in second typed parameter). |
@wojciechkrol Okay, I see what you did. In that case, I think the code is alright. No objections from my side :) |
After one night of sleep, allow me to once more explain why I still like the implementation by ingvardm a little bit better. It makes If I define the handler function as If I define it as If I define it as If I define it as If I define it as I know that all of this is also possible with the implementation in #29, but it is more complicated. Especially because there are now two typed parameters |
Changes made in #29 |
This PR should fix issue #8 and other issues regarding event types and callback arguments.