Skip to content
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

[utils] Improve type inference of useForkRef #31845

Merged
merged 1 commit into from
Mar 22, 2022

Conversation

eps1lon
Copy link
Member

@eps1lon eps1lon commented Mar 16, 2022

Currently instances in ref callbacks are allowed to be nullable due to our bivariance hack. However, during runtime these instances can be null: https://codesandbox.io/s/refs-are-nullable-m44vxx

We'll likely remove the bivariance hack to catch these issues in the future. In the meantime, existing packages and tests should guard against nullable instances regardless.

The issue was first reported in DefinitelyTyped/DefinitelyTyped#58464

@eps1lon eps1lon added typescript package: utils Specific to the @mui/utils package labels Mar 16, 2022
@@ -72,7 +72,7 @@ function useSelect<TValue>(props: UseSelectParameters<TValue>) {
}
}, [listboxFocusRequested]);

const updateListboxRef = (listboxElement: HTMLUListElement) => {
const updateListboxRef = (listboxElement: HTMLUListElement | null) => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was unsound

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would basically need to always add | null when using ref callbacks no?

@@ -154,7 +154,7 @@ const Link = React.forwardRef(function Link(inProps, ref) {
as={component}
onBlur={handleBlur}
onFocus={handleFocus}
ref={handlerRef}
ref={handleRef}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a typo-drive-by-fix

@@ -115,7 +115,7 @@ const Link = React.forwardRef(function Link(inProps, ref) {
ref: focusVisibleRef,
} = useIsFocusVisible();
const [focusVisible, setFocusVisible] = React.useState<boolean>(false);
const handlerRef = useForkRef(ref, focusVisibleRef) as React.RefObject<HTMLSpanElement>;
const handleRef = useForkRef(ref, focusVisibleRef) as React.Ref<HTMLSpanElement>;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cast was unsound generally but also technically incorrect at runtime. useForkRef returns a function not an object (though the specific implementation is irrelevant. What's import is, that it's a generic ref).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch

@eps1lon eps1lon force-pushed the fix/ref-bivariance branch from f8eac87 to 4b5d2bb Compare March 16, 2022 20:50
export default function useForkRef<InstanceA, InstanceB>(
refA: React.Ref<InstanceA> | null | undefined,
refB: React.Ref<InstanceB> | null | undefined,
): React.Ref<InstanceA & InstanceB> | null {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helps TypeScript with inference with the proposed changes in DefinitelyTyped/DefinitelyTyped#58936.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, this will basically create a union of the two in case they are different 👍

@mui-bot
Copy link

mui-bot commented Mar 16, 2022

No bundle size changes

Generated by 🚫 dangerJS against 4b5d2bb

@eps1lon eps1lon marked this pull request as ready for review March 16, 2022 22:10
@eps1lon eps1lon mentioned this pull request Mar 22, 2022
1 task
Copy link
Member

@mnajdova mnajdova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good, looks like we will need to do more for the actual upgrade to the latest @types/react, but I will be pushing the changes in separate PRs.

@mnajdova mnajdova merged commit 1470c72 into mui:master Mar 22, 2022
@eps1lon eps1lon deleted the fix/ref-bivariance branch March 22, 2022 15:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: utils Specific to the @mui/utils package typescript
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants