-
-
Notifications
You must be signed in to change notification settings - Fork 32.5k
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
[Popper] Convert code to typescript #34771
[Popper] Convert code to typescript #34771
Conversation
Resolve #34718 |
|
function resolveAnchorEl(anchorEl) { | ||
function resolveAnchorEl( | ||
anchorEl: VirtualElement | (() => VirtualElement) | ||
): any { |
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.
Not sure how to resolve this any
. Seems like anchorEl
has the type HTMLElement | VirtualElement | (() => HTMLElement | VirtualElement)
but the current code treat it as HTMLElement | (() => HTMLElement)
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.
while the original signature put it as VirtualElement | (() => VirtualElement)
. Is there a potential bug here?
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.
You can define the resolveAnchorEl
as an overloaded function:
function resolveAnchorEl(anchorEl: VirtualElement | (() => VirtualElement)): VirtualElement;
function resolveAnchorEl(anchorEl: HTMLElement | (() => HTMLElement)): HTMLElement;
function resolveAnchorEl(anchorEl: VirtualElement | (() => VirtualElement) | HTMLElement | (() => HTMLElement)): HTMLElement | VirtualElement {
return typeof anchorEl === 'function' ? anchorEl() : anchorEl;
}
and define a type guard checking if an element is a DOM element;
function isHTMLElement(element: HTMLElement | VirtualElement): element is HTMLElement {
return (element as HTMLElement).nodeType !== undefined;
}
then, after resolving the anchorEl check if it's an HTMLElement:
-if (resolvedAnchorEl && resolvedAnchorEl.nodeType === 1) {
+if (resolvedAnchorEl && isHTMLElement(resolvedAnchorEl) && resolvedAnchorEl.nodeType === 1) {
Similarly, in PopperUnstyled body, where container
is defined, check if we're dealing with HTMLElement or VirtualElement. You can pass in null
to ownerDocument
if anchorEl
is a VirtualElement.
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 resolved this issue
@@ -106,6 +110,8 @@ export interface PopperUnstyledOwnProps { | |||
* @default false | |||
*/ | |||
transition?: boolean; | |||
|
|||
ownerState?: PopperUnstyledOwnerState; |
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.
Added this to pass type check here https://github.com/danhuynhdev/material-ui/blob/2b0f1d9684abd308de1e3c05e8bec4aaa13993f5/packages/mui-base/src/PopperUnstyled/PopperUnstyled.test.tsx#L38
But then I still have to pass ownerState
as any. Not sure how to properly handle this as I'm not familiar with ownerState
. From other places, it seems like ownerState
isn't passed in as a prop but constructed inside the component. But I do not see that in this component.
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.
Yeah, something seems to be off here. You should not have ownerState
as a prop. I'll try to correct the code in the separate PR and you'll be able to rebase on top of my fixes.
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.
Have you taken a look a what's wrong here? Happy to fix that myself if I can understand the context here.
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.
It turned out to be a bigger problem that affects several components, and we haven't figured out what would be the best solution here.
In short, we generally don't want to expose ownerState
as a prop, because users of the components should not manually set it. However, in some cases, when an MUI Base component is used in a slot of another component, it will receive the ownerState (as all slot components do). The type of this ownerState
is not PopperUnstyledOwnerState
, though - it's a state of a component that owns the slots, so it's impossible to type this strongly.
For now, let's define ownerState?: object
in PopperUnstyledOwnProps
. When we decide how to solve the problem for good, we'll revisit this part. This should allow you to drop as any
from tests.
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.
Sorry for the late response. I have updated the code but unfortunately, ownerState?: object
isn't compatible with downstream type, as they expect a concrete interface. So I have to put it as any
again, i guess it's the same as object
here as we cannot guarantee typesafe-ness here.
2b0f1d9
to
a25626e
Compare
> In short, we generally don't want to expose ownerState as a prop, because users of the components should not manually set it. However, in some cases, when an MUI Base component is used in a slot of another component, it will receive the ownerState (as all slot components do). The type of this ownerState is not PopperUnstyledOwnerState, though - it's a state of a component that owns the slots, so it's impossible to type this strongly.
Thanks, this looks pretty good! There's a problem with the CI build, though. It needs the |
The |
I corrected and simplified the code in a few places. I think it's good to go now. Thanks for your contribution, @danhuynhdev! |
Resolve #34718