@types/react@17.0.41 breaks forwarding polymorphic component refs
See original GitHub issueDuplicates
- I have searched the existing issues
Latest version
- I have tested the latest version
Current behavior 😯
Given the following code (that wraps a MUI component and uses forwardRef
to pass the ref down):
import { forwardRef } from "react";
import Paper, { PaperProps } from "@mui/material/Paper";
import Container from "@mui/material/Container";
export interface HeaderProps
extends Omit<PaperProps, "elevation" | "square" | "component" | "variant"> {
elevation?: number;
}
export const Header = forwardRef<HTMLDivElement, HeaderProps>(
({ children, elevation = 2, sx, ...props }, ref) => (
<Paper
ref={ref}
component="header"
square
elevation={elevation}
sx={{ padding: 2, ...sx }}
{...props}
>
<Container>{children}</Container>
</Paper>
)
);
This code works fine but when you update a project to use @types/react@17.0.41
then the following TS error will display (for the ref={ref}
line):
src/Header.tsx:12:5 - error TS2769: No overload matches this call.
Overload 1 of 2, '(props: { component: "header"; } & { children?: ReactNode; classes?: Partial<PaperClasses> | undefined; elevation?: number | undefined; square?: boolean | undefined; sx?: SxProps<...> | undefined; variant?: "elevation" | ... 1 more ... | undefined; } & CommonProps & Omit<...>): Element', gave the following error.
Type 'ForwardedRef<HTMLDivElement>' is not assignable to type 'RefCallback<HTMLElement> | RefObject<HTMLElement> | null | undefined'.
Type '(instance: HTMLDivElement | null) => void' is not assignable to type 'RefCallback<HTMLElement> | RefObject<HTMLElement> | null | undefined'.
Type '(instance: HTMLDivElement | null) => void' is not assignable to type 'RefCallback<HTMLElement>'.
Types of parameters 'instance' and 'instance' are incompatible.
Type 'HTMLElement | null' is not assignable to type 'HTMLDivElement | null'.
Property 'align' is missing in type 'HTMLElement' but required in type 'HTMLDivElement'.
Overload 2 of 2, '(props: DefaultComponentProps<PaperTypeMap<{}, "div">>): Element', gave the following error.
Type '{ children: Element; key?: Key | null | undefined; id?: string | undefined; color?: string | undefined; translate?: "yes" | "no" | undefined; hidden?: boolean | undefined; ... 254 more ...; sx: { ...; } | ... 5 more ... | { ...; }; }' is not assignable to type 'IntrinsicAttributes & { children?: ReactNode; classes?: Partial<PaperClasses> | undefined; elevation?: number | undefined; square?: boolean | undefined; sx?: SxProps<...> | undefined; variant?: "elevation" | ... 1 more ... | undefined; } & CommonProps & Omit<...>'.
Property 'component' does not exist on type 'IntrinsicAttributes & { children?: ReactNode; classes?: Partial<PaperClasses> | undefined; elevation?: number | undefined; square?: boolean | undefined; sx?: SxProps<...> | undefined; variant?: "elevation" | ... 1 more ... | undefined; } & CommonProps & Omit<...>'.
12 <Paper
~~~~~~
13 ref={ref}
~~~~~~~~~~~~~~~
...
18 {...props}
~~~~~~~~~~~~~~~~
19 >
~~~~~
node_modules/typescript/lib/lib.dom.d.ts:6192:5
6192 align: string;
~~~~~
'align' is declared here.
node_modules/@types/react/index.d.ts:824:46
824 ? PropsWithoutRef<P> & { ref?: Exclude<R, string> | undefined }
~~~
The expected type comes from property 'ref' which is declared here on type 'IntrinsicAttributes & { component: "header"; } & { children?: ReactNode; classes?: Partial<PaperClasses> | undefined; elevation?: number | undefined; square?: boolean | undefined; sx?: SxProps<...> | undefined; variant?: "elevation" | ... 1 more ... | undefined; } & CommonProps & Omit<...>'
Found 1 error in src/Header.tsx:12
Removing component="header"
from the props will make the error disappear. So the polymorphic nature of Paper
seems to be an issue here.
This works for example:
export const Header = forwardRef<HTMLDivElement, HeaderProps>(
({ children, elevation = 2, sx, ...props }, ref) => (
<Paper
ref={ref}
square
elevation={elevation}
sx={{ padding: 2, ...sx }}
{...props}
>
<Container>{children}</Container>
</Paper>
)
);
But as soon as I add component="header"
back it fails. Changing HTMLDivElement
to HTMLElement
would appear to be the correct way forward but it still errors.
Expected behavior 🤔
No response
Steps to reproduce 🕹
Repo here: https://github.com/robcaldecott/mui-polymorphic-ref-ts-error
Context 🔦
No response
Your environment 🌎
`npx @mui/envinfo`
System:
OS: macOS 10.15.7
Binaries:
Node: 16.13.2 - ~/.nvm/versions/node/v16.13.2/bin/node
Yarn: 1.22.17 - ~/.nvm/versions/node/v16.13.2/bin/yarn
npm: 8.5.2 - ~/.nvm/versions/node/v16.13.2/bin/npm
Browsers:
Chrome: 99.0.4844.83
Edge: Not Found
Firefox: 96.0.2
Safari: 14.1.2
npmPackages:
@emotion/react: ^11.8.2 => 11.8.2
@emotion/styled: ^11.8.1 => 11.8.1
@mui/base: 5.0.0-alpha.73
@mui/material: ^5.5.2 => 5.5.2
@mui/private-theming: 5.4.4
@mui/styled-engine: 5.5.2
@mui/system: 5.5.2
@mui/types: 7.1.3
@mui/utils: 5.4.4
@types/react: ^17.0.41 => 17.0.41
react: ^17.0.2 => 17.0.2
react-dom: ^17.0.2 => 17.0.2
typescript: ^4.5.4 => 4.6.2 ```
</details>
Issue Analytics
- State:
- Created 2 years ago
- Comments:9 (9 by maintainers)
Top Results From Across the Web
Forwarding refs for a polymorphic React component in ...
How to properly type polymorphic React components using forwardRef in TypeScript.
Read more >Build strongly typed polymorphic components with React and ...
Learn how to build strongly typed polymorphic React components with TypeScript, using familiar Chakra UI and MUI component props as guides.
Read more >Intermediate TypeScript and React Handbook – How to Build ...
Hey everyone! In this detailed guide, I'll show you how to build strongly typed Polymorphic React components with Typescript.
Read more >Create a Polymorphic Component with Typescript and React
rest}>{children}</Element>; };. Now we wrap the whole thing in forwardRef, add our ref prop, and we're done. const Box: PolymorphicComponent = ...
Read more >How can I contstrain the props when using Polymorphic ...
Based on this great article, "Forwarding refs for a polymorphic React component in TypeScript" I've been trying to create a Polymorphic ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Fixed in
@types/react^17.0.42
(might take a bit until released)Ah, I thought it is
head
, by bad. This is going to be an interesting issue then. With the latest @types/react changes, as far as I understood you cannot set ref of a subtype to a variable accepting a ref of a supertype (for exampleHTMLElement
as you assumed).I am adding the use-case as a test in our codebase to ensure it will work with the changes we are preparing.