-
-
Notifications
You must be signed in to change notification settings - Fork 356
[Live] Add signature overload for on and off methods of component #1685
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
Conversation
Thank you for that @YummYume ! Could you rebuild the dist file ? It feels you updated those files "manually" (i may be wrong on this, TS is not my strongest force 😅 ) From the root of the monorepo, this should be enough i think npm run build (This is why the CI is red |
This is weird 🤔 I didn't touch the No idea why the LiveComponent tests aren't passing, though, they're all green. |
Related to dependencies / Symfony 7.1.. and don't bother with Autocomplete if you're not working on it ... or you won't ever end this PR haha |
@@ -55,7 +55,7 @@ export default class { | |||
}; | |||
} | |||
|
|||
const timer = setInterval(() => { | |||
const timer = window.setInterval(() => { |
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 am not sure about this fix. setInterval is native function well supported why use the one from window?
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.
Using setInterval
or window.setInterval
results in the same thing in a browser context. However, when using setInterval
, TypeScript was mistakenly thinking that this was the Nodejs setInterval
function, which doesn't return a number like in a browser, which was causing a typing error warning during builds.
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.
Ok thanks for your answer!
@@ -30,8 +33,34 @@ export default class Component { | |||
addPlugin(plugin: PluginInterface): void; | |||
connect(): void; | |||
disconnect(): void; | |||
on(hookName: string, callback: (...args: any[]) => void): void; | |||
off(hookName: string, callback: (...args: any[]) => void): void; | |||
on(hookName: 'connect', callback: (component: Component) => MaybePromise): void; |
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.
Instead of having all of those definitions why not just use type ComponentHookName?
on(hookName: ComponentHookName, callback: (component: Component) => MaybePromise): void;
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.
Because the callbacks receive different arguments depending on the event. By explicitly overloading this method, TypeScript (and your IDE) now knows which events are available, and the arguments that they each receive. It's a much nicer developer experience, and it should work for any IDE even when not using TypeScript.
@@ -122,11 +126,31 @@ export default class Component { | |||
* * loading.state:finished (element: HTMLElement) => {} | |||
* * model:set (model: string, value: any, component: Component) => {} | |||
*/ | |||
on(hookName: string, callback: (...args: any[]) => void): void { | |||
on(hookName: 'connect', callback: (component: Component) => MaybePromise): void; |
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.
What do you think about adding callback types too? Like ConnectHook
or ConnectCallback
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.
Just a suggestion, I'm not so comfortable with TypeScript, but what would you think about something like that?
type Hooks = {
'connect': (component: Component) => MaybePromise,
'disconnect': (component: Component) => MaybePromise,
'request:started': (requestConfig: any) => MaybePromise
'render:finished': (component: Component) => MaybePromise
'response:error': (backendResponse: BackendResponse, controls: {displayError: boolean}) => MaybePromise
'loading.state.started': (element: HTMLElement, request: BackendRequest) => MaybePromise
'loading.state.finished': (element: HTMLElement) => MaybePromise
'model:set': (model: string, value: any, component: Component) => MaybePromise,
}
type ComponentHookName = keyof Hooks;
type HookCallback<T extends string> = T extends ComponentHookName
? Hooks[T]
: (...args: any[]) => MaybePromise;
class Component {
on<T extends ComponentHookName|string>(name: T, callback: HookCallback<T>): void {
this.hooks.register(hookName, callback);
}
off<T extends ComponentHookName|string>(name: T, callback: HookCallback<T>): void {
this.hooks.unregister(hookName, callback);
}
}
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.
Hi @squrious ! I tested this approach, and after a few tweaks, it gives the same result as the current implementation, and is a bit easier to use for maintaining many events, rather than overloading the methods manually. I personally wouldn't be opposed to it. 😄
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.
Nice 😄
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.
So I went ahead and implemented your idea with the conditional, it's way more maintainable and achieves the same thing. 👍
1062315
to
de5dbd2
Compare
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.
Sounds good to me! Thanks a lot @YummYume!
@@ -55,7 +55,7 @@ export default class { | |||
}; | |||
} | |||
|
|||
const timer = setInterval(() => { | |||
const timer = window.setInterval(() => { |
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.
Ok thanks for your answer!
de5dbd2
to
3c17279
Compare
Awesome first contribution @YummYume, thank you! |
Following some feedback in #1676. This PR only affects TypeScript typing.
Provides automatic typing for the
on
andoff
events of a component, depending on the event's name. Also changes the return type allowed from an event listener to allow passing an asynchronous function. This is a pretty common thing to do (the need to useawait
), but TypeScript/linters will often yell at you for doing so if the event listener does not expect aPromise
to be returned.(also fixed a typing issue with
NodeJS.Timer
being used instead ofnumber
)