-
-
Notifications
You must be signed in to change notification settings - Fork 246
feat: Add Messenger parent
parameter
#6142
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
4ff719e
to
f3e18ba
Compare
parant
parameterparent
parameter
2dd241a
to
6729773
Compare
1e6b6ab
to
d6f1dc4
Compare
f3e18ba
to
04b2069
Compare
b9bef02
to
f980adf
Compare
0a293cd
to
11eece3
Compare
f980adf
to
61f5053
Compare
11eece3
to
f057a12
Compare
eb8e095
to
764f8e9
Compare
Type tests can be found on this branch: https://github.com/MetaMask/core/tree/add-messenger-type-tests-parent |
Namespace extends string, | ||
Action extends ActionConstraint, | ||
Event extends EventConstraint, | ||
Parent extends Messenger< |
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.
This is a new addition from what was described in the ADR. As you can see in the tests, it does make using this a bit more verbose, but it's not too bad IMO. This was the only way I could find to validate that the parent had all necessary actions/events (this was validated in the constructor params, but the method of validation relied on there being a generic type param to validate against).
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.
Makes sense given how we've designed Messenger
. I can't think of another way to do this. We can use the typeof
trick you used in the tests, though, to make providing this type easier.
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.
LGTM!
string, | ||
ActionConstraint, | ||
EventConstraint, | ||
// Use `any` to avoid preventing a parent from having a parent. `any` is harmless in a type |
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.
This does work, but wouldn't leaving this type parameter out also work? Then the default would be never
which seems more accurate.
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 was hesitant to do this because there is nothing really stopping someone from writing a messenger that is both a parent and has a parent. It might even be a reasonably good design. For example, if the TransactionController
wanted to have internal messengers for each helper class it uses, they might delegate to the main transaction controller messenger so their actions/events can be used internally in the transaction controller.
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.
Ah, I missed the double negative. "Avoid preventing". Got it :)
Yes I agree we should make it possible to essentially create a delegation chain.
} | ||
this.#registerActionHandler(actionType, handler); | ||
if (this.#parent) { | ||
// @ts-expect-error The parent type isn't constructed in a way that proves it supports this |
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 feel like there ought to be a way to align the types so this isn't necessary, but I don't know how. I tried changing the type of #parent
from DelegatedMessenger
to Parent
but then the if (messenger === this.#parent) {
statement you added at the beginning of revoke
failed because TypeScript thought there was no overlap between the two values. So it seems that we need @ts-expect-error
somewhere...
I do agree this seems type-safe though given the check we have in the constructor.
Namespace extends string, | ||
Action extends ActionConstraint, | ||
Event extends EventConstraint, | ||
Parent extends Messenger< |
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.
Makes sense given how we've designed Messenger
. I can't think of another way to do this. We can use the typeof
trick you used in the tests, though, to make providing this type easier.
*/ | ||
export class Messenger< | ||
Namespace extends string, | ||
Action extends ActionConstraint, |
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.
Side note, but should Action
and Event
default to never
so that if you don't supply any type parameters to Messenger
, allowing TypeScript to infer them, you don't end up with a messenger that recognizes all actions and 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.
Good idea. I will try this separately
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.
Done here: #6311
ad2eab7
to
29d3a01
Compare
Add the `parent` constructor parameter to the `Messenger` class for automatic delegation of all capabilities under that messenger's namespace. This significantly reduces boilerplate, making the messenger easier to use in a similar manner to how the old `RestrictedMessenger` class wored. See this ADR PR for details: MetaMask/decisions#53
29d3a01
to
dfa154b
Compare
## Explanation The action and event type parameters for the new `@metamask/messenger` package's Messenger class now default to `never`. This should make it harder to accidentally create a messenger with overly broad inferred types, making it less type safe than the author might expect. The `Messenger` classes in `@metamask/base-controller` were not changed to avoid breaking changes. While this change itself wouldn't really be breaking by most definitions, it would require changes due to our use of the `@typescript-eslint/no-unnecessary-type-arguments` lint rule. ## References This was a suggestion from here: #6142 (comment) ## Checklist - [x] I've updated the test suite for new or updated code as appropriate - [x] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [x] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/contributing.md#updating-changelogs), highlighting breaking changes as necessary - [x] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes
Explanation
Add the
parent
constructor parameter to theMessenger
class for automatic delegation of all capabilities under that messenger's namespace. This significantly reduces boilerplate, making the messenger easier to use in a similar manner to how the oldRestrictedMessenger
class wored.See this ADR PR for details: MetaMask/decisions#53
References
Depends upon #6132
Relates to #5626
Checklist