Add `type` field to the router event object
See original GitHub issueWhich @angular/* package(s) are relevant/releated to the feature request?
router
Description
I have a piece of code that gets invoked by user with router as a parameter. In that code I subscribe to router events. If an app is minified, constructor names of events are obfuscated and then I need to do some naive checking like
function isNavigationEnd(event: Event): event is NavigationEnd {
return event["constructor"]["name"] === RouterEvents.NAVIGATION_END
|| ("id" in event
&& typeof event["id"] === "number"
&& !!event["url"]
&& "urlAfterRedirects" in event
&& !!event["urlAfterRedirects"]
&& objectKeys(event).length === 3);
}
I am not so familiar with angular.
The issue I currently have is that I do some action in RouteConfigLoadStart
and keep a reference to it
and I clean that reference in NavigationCancel
or NavigationEnd
Now for some reason NavigationEnd
or NavigationCancel
never happens and references keep growing when I enter the RouteConfigLoadStart
.
If event constructor names would be preserved I would know which event I am currently working with and could easier do the logic.
Keep in mind that my piece of code is external to the angular app, and it gets called with router as a parameter, so I am not in an non obfuscated environment of the app.
Proposed solution
Add a type
field to the event or preserve name of its constructor.
Alternatives considered
I am using an alternative to do the naive checking but some events have same fields and then it could match more events than it should.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:21
- Comments:15 (8 by maintainers)
Top GitHub Comments
Unfortunately, configuration adjustments are not easily done (i.e., not without moving off the supported path with the Angular CLI at least) and it can result in large size regressions in applications while also being complex to correctly configure. It would also require all consuming applications to be adequately configured for this particular library’s use case since the class originates from the application’s code via
@angular/router
and not the library’s code. Constructor/function names are not particularly reliable in the general case as different functions can have the same name but provide completely different functionality. Optimizations can also inline or otherwise modify certain code constructs resulting in names no longer existing. That is probably not overly relevant in this case but making assumptions based on name or toString, regardless of optimization, can lead to broken runtime behavior.The addition of the
type
property as a type guard on the router event classes could also provide some potential ergonomic improvements as well. For example, instead of needing multipleif
statements withinstanceof
checks when handling multiple event classes, a switch statement withtype
could be used instead with TypeScript narrowing based on thecase
statement.Just to throw in another (admittedly also not pretty) workaround: since your users need to call an init function from their Angular app, you could extend that to pass all relevant objects to which you need access:
This snippet would even always be exactly the same for the user, so to hide that you could also offer a small Angular library for them to add which wraps the init function and passes the types along internally. Since that library (which really only contains a single function) is compiled as part of their app, nothing really changes regarding how they use your library. The only thing that changes for them is that they add a tiny dependency exposing the init function rather than calling an unknown global function.
They way your actual library essentially receives a lookup table.