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

[Box] Type error when too many properties exist in JSX.IntrinsicElements #34068

Closed
2 tasks done
Methuselah96 opened this issue Aug 25, 2022 · 36 comments · Fixed by #38168 or #43384
Closed
2 tasks done

[Box] Type error when too many properties exist in JSX.IntrinsicElements #34068

Methuselah96 opened this issue Aug 25, 2022 · 36 comments · Fixed by #38168 or #43384
Assignees
Labels
bug 🐛 Something doesn't work component: Box The React component. package: system Specific to @mui/system typescript

Comments

@Methuselah96
Copy link
Contributor

Methuselah96 commented Aug 25, 2022

Duplicates

  • I have searched the existing issues

Latest version

  • I have tested the latest version

Current behavior 😯

The Box component produces type errors when too many properties are added to JSX.IntrinsicElements.

Expected behavior 🤔

The Box component should not produce type error when properties are added to JSX.IntrinsicElements.

Steps to reproduce 🕹

When using @mui/material in the same project with @react-three/fiber and @react-three/drei using the Box component produces a type error:

error TS2590: Expression produces a union type that is too complex to represent.
import React from 'react';
import { Box } from '@mui/material';
import { Canvas } from '@react-three/fiber';
import { OrbitControls } from '@react-three/drei';

function Root() {
  return (
    <Box sx={{ m: 1 }}>
      <Canvas>
        <OrbitControls />
      </Canvas>
    </Box>
  );
}
Output
import React from 'react';
import { Box } from '@mui/material';
import { Canvas } from '@react-three/fiber';
import { OrbitControls } from '@react-three/drei';
function Root() {
    return (React.createElement(Box, { sx: { m: 1 } },
        React.createElement(Canvas, null,
            React.createElement(OrbitControls, null))));
}
Compiler Options
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "declaration": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "target": "ES2017",
    "jsx": "react",
    "module": "ESNext",
    "moduleResolution": "node"
  }
}

Playground Link: Provided

This behavior can also be replicated without any dependence on @react-three/fiber or @react-three/drei by adding properties to JSX.IntrinsicElements:

import React from 'react';
import { Box } from '@mui/material';

declare global {
  namespace JSX {
    interface IntrinsicElements {
      test1: number;
      test2: number;
      test3: number;
      test4: number;
      test5: number;
      test6: number;
      test7: number;
      test8: number;
      test9: number;
      test10: number;
      test11: number;
      test12: number;
      test13: number;
      test14: number;
      test15: number;
      test16: number;
      test17: number;
      test18: number;
      test19: number;
      test20: number;
      test21: number;
      test22: number;
      test23: number;
      test24: number;
      test25: number;
      test26: number;
      test27: number;
      test28: number;
      test29: number;
      test30: number;
      test31: number;
      test32: number;
      test33: number;
      test34: number;
      test35: number;
      test36: number;
      test37: number;
      test38: number;
      test39: number;
      test40: number;
      test41: number;
      test42: number;
      test43: number;
      test44: number;
      test45: number;
      test46: number;
      test47: number;
      test48: number;
      test49: number;
      test50: number;
      test51: number;
      test52: number;
      test53: number;
      test54: number;
      test55: number;
      test56: number;
      test57: number;
      test58: number;
      test59: number;
      test60: number;
      test61: number;
      test62: number;
      test63: number;
      test64: number;
      test65: number;
      test66: number;
      test67: number;
      test68: number;
      test69: number;
      test70: number;
      test71: number;
      test72: number;
      test73: number;
      test74: number;
      test75: number;
      test76: number;
      test77: number;
      test78: number;
      test79: number;
      test80: number;
      test81: number;
      test82: number;
      test83: number;
      test84: number;
      test85: number;
      test86: number;
      test87: number;
      test88: number;
      test89: number;
      test90: number;
      test91: number;
      test92: number;
      test93: number;
      test94: number;
      test95: number;
      test96: number;
      test97: number;
      test98: number;
      test99: number;
      test100: number;
      test101: number;
      test102: number;
      test103: number;
      test104: number;
      test105: number;
      test106: number;
      test107: number;
      test108: number;
      test109: number;
      test110: number;
      test111: number;
      test112: number;
      test113: number;
      test114: number;
      test115: number;
      test116: number;
      test117: number;
      test118: number;
      test119: number;
      test120: number;
      test121: number;
      test122: number;
      test123: number;
      test124: number;
      test125: number;
      test126: number;
      test127: number;
      test128: number;
      test129: number;
      test130: number;
      test131: number;
      test132: number;
      test133: number;
      test134: number;
      test135: number;
      test136: number;
      test137: number;
      test138: number;
      test139: number;
    }
  }
}

function Root() {
  return <Box sx={{ m: 1 }} />;
}
Output
import React from 'react';
import { Box } from '@mui/material';
function Root() {
    return React.createElement(Box, { sx: { m: 1 } });
}
Compiler Options
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "declaration": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "target": "ES2017",
    "jsx": "react",
    "module": "ESNext",
    "moduleResolution": "node"
  }
}

Playground Link: Provided

Context 🔦

This is primarily in the context of trying to use @react-three/fiber and @react-three/drei in the same project as @mui/material. Related issues include #29176 and https://stackoverflow.com/questions/68692230/ts-expression-produces-a-union-type-that-is-too-complex-to-represent-with-materi. The latter issue seems to suggest this has been resolved, but I do not believe it has been.

Your environment 🌎

tsconfig.json included above.

@Methuselah96 Methuselah96 added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Aug 25, 2022
@Methuselah96 Methuselah96 changed the title Box prdouces type error when too many properties exist in JSX.IntrinsicElements Box produces type error when too many properties exist in JSX.IntrinsicElements Aug 25, 2022
@Methuselah96
Copy link
Contributor Author

Methuselah96 commented Aug 26, 2022

For those facing this issue, I was able to workaround it by patching Box.d.ts like so:

  *
  * - [Box API](https://mui.com/material-ui/api/box/)
  */
-declare const Box: OverridableComponent<BoxTypeMap>;
+declare const Box: <D extends React.ElementType = 'div'>(props: BoxProps<D> & { component?: D }) => JSX.Element;
 
 export type BoxProps<
   D extends React.ElementType = BoxTypeMap['defaultComponent'],

I'm not sure if this is a good long-term fix, but it seems to work from what I can tell. I suppose the way OverridableComponent is defined produces too complex of a union type.

@Methuselah96
Copy link
Contributor Author

Methuselah96 commented Aug 26, 2022

The above solution does seem to lose automatic typing for event handlers (i.e., the type of the event argument for onContextMenu for a normal div Box is not automatically inferred), but it is much better then it not being able to type-check at all.

@michaldudak michaldudak added package: system Specific to @mui/system component: Box The React component. labels Aug 26, 2022
@fishuke
Copy link

fishuke commented Oct 24, 2022

I have the same problem with the latest version (npm).

I created a component for a workaround if anyone wants to use it:

// ** MUI Imports
import MuiBox from '@mui/material/Box'
import {BoxProps} from '@mui/material/Box'

const Box = (props: BoxProps) => {
  return (
    <MuiBox
      {...props}
      component="div"
    />
  )
}

export type {BoxProps}

export default Box

@siriwatknp siriwatknp added typescript and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Dec 19, 2022
@siriwatknp
Copy link
Member

Does it happen with only Box component?

@Methuselah96
Copy link
Contributor Author

Yes.

@mpn7
Copy link

mpn7 commented Jan 3, 2023

Any news on this? I haven't found any solution to this, only workarounds.

@zaesur
Copy link

zaesur commented Jan 25, 2023

Any news on this? I haven't found any solution to this, only workarounds.

I'm working on a large code base and changing the imports or updating the component type everywhere is not deemed acceptable, so I am also still looking for a real solution.

@shinitakunai
Copy link

shinitakunai commented Feb 18, 2023

I have a workaround by patching the Box.d.ts type in @mui/material, @mui/system, and @material-core with patch-package and replacing the types with

-declare const Box: OverridableComponent<BoxTypeMap>;
+// declare const Box: OverridableComponent<BoxTypeMap>;
 
 export type BoxProps<
   D extends React.ElementType = BoxTypeMap['defaultComponent'],
   P = {},
 > = OverrideProps<BoxTypeMap<P, D>, D>;
 
-export default Box;
+export default function Box(props: BoxProps): JSX.Element;

@fgarrec0397
Copy link

I have a workaround by patching the Box.d.ts type in @mui/material, @mui/system, and @material-core with patch-package and replacing the types with

-declare const Box: OverridableComponent<BoxTypeMap>;
+// declare const Box: OverridableComponent<BoxTypeMap>;
 
 export type BoxProps<
   D extends React.ElementType = BoxTypeMap['defaultComponent'],
   P = {},
 > = OverrideProps<BoxTypeMap<P, D>, D>;
 
-export default Box;
+export default function Box(props: BoxProps): JSX.Element;

Worked fine for me and I think it's the cleaner workaround for now

@luckysw0rd
Copy link

I have a workaround by patching the Box.d.ts type in @mui/material, @mui/system, and @material-core with patch-package and replacing the types with

-declare const Box: OverridableComponent<BoxTypeMap>;
+// declare const Box: OverridableComponent<BoxTypeMap>;
 
 export type BoxProps<
   D extends React.ElementType = BoxTypeMap['defaultComponent'],
   P = {},
 > = OverrideProps<BoxTypeMap<P, D>, D>;
 
-export default Box;
+export default function Box(props: BoxProps): JSX.Element;

This update was involved on @mui/material^5.11.10?

@MDransfeld
Copy link

MDransfeld commented Jul 20, 2023

With the mui 5.14.1 update this error occurs on even more components, e.g. ToggleButton, Typography, Card, Divider, etc.
Version 5.14.0 was fine.

@schimi-dev
Copy link

Yeah, while with 5.14.0 it only concerned Box and it was quite ok to work around this, with 5.14.1 it seems like a real issue/problem concerning many Mui components.

@Methuselah96
Copy link
Contributor Author

Methuselah96 commented Jul 20, 2023

It looks like this was caused by these added lines in #35924. The patch to fix it would be to remove the added lines in OverrideComponent.d.ts, but that obviously runs counter to the point of the PR.

@michaldudak michaldudak changed the title Box produces type error when too many properties exist in JSX.IntrinsicElements [Box] produces type error when too many properties exist in JSX.IntrinsicElements Jul 26, 2023
@michaldudak michaldudak added the bug 🐛 Something doesn't work label Jul 26, 2023
@michaldudak michaldudak changed the title [Box] produces type error when too many properties exist in JSX.IntrinsicElements [Box] Type error when too many properties exist in JSX.IntrinsicElements Jul 26, 2023
@Methuselah96
Copy link
Contributor Author

Methuselah96 commented Aug 12, 2023

@michaldudak Can you reopen this issue, since the fix was reverted in #38356?

@michaldudak
Copy link
Member

Yes, of course.

@michaldudak michaldudak reopened this Aug 14, 2023
@Methuselah96
Copy link
Contributor Author

Methuselah96 commented Aug 22, 2023

@michalmuchakr What version are you on? This error is known to occur for other components in 5.14.1, but has since been fixed.

@michalmuchakr
Copy link

michalmuchakr commented Aug 23, 2023

I'm using "@mui/material": "5.14.5".

@michaldudak
Copy link
Member

@michalmuchakr, could you create a codesandbox showing the issue? I'm surprised the problem exists in TextField.

@pixelass
Copy link
Contributor

pixelass commented Oct 19, 2023

We experienced this issue in joy-ui but somehow it just happened yesterday and we've been updating the betas on each new release 🤷 . Now when I roll back I can still see the issue. After a lot of refactoring we had to remove ALL usages of Box and mostly use this now:

const Box = styled("div")({}) // Some style

So generally Box is completely broken for us.

This cost us a lot of nerv and unplanned refactoring.

Please prioritize this issue as it can/will break a lot of big projects.

I'm a bit scared to check which new bugs were introduced by the refactoring but hopefully our tests will catch them.

❤️


EDIT: this is probably helpful ;)

    "@mui/base": "5.0.0-beta.20",
    "@mui/icons-material": "5.14.14",
    "@mui/joy": "5.0.0-beta.11",
    "@mui/material": "5.14.14",

@michaldudak
Copy link
Member

@pixelass Does the issue exist when you explicitly provide a component prop to the Box?

@pixelass
Copy link
Contributor

pixelass commented Oct 27, 2023

@pixelass Does the issue exist when you explicitly provide a component prop to the Box?

It seems to have happened after the project reached a certain size. Not sure if that makes sense.

Unrelated to whether props were added or not. Suddenly ALL instances were affected.

@michaldudak
Copy link
Member

To be clear - the instances of the Box where you have both the sx and component prop (such as <Box sx={{ m: 1 }} component='div' />) trigger a TypeScript error, yes?

@pixelass
Copy link
Contributor

@michaldudak all instances of Box suddenly triggered that issue.

<Box>Foo</Box>
<Box sx={{m: 2}}>Foo</Box>
<Box component="footer">Foo</Box>
<Box data-testid="foo">Foo</Box>

I would have to checkout an older version of a closed source project to be sure though.
I just did a find & replace at some point, since they started popping up one after another.

I would love to create a repro, but I will have to see when I find time, since this is a rather strange and somewhat hard to reproduce.

@pixelass
Copy link
Contributor

pixelass commented Nov 2, 2023

@michaldudak Out of nothing this just happened:
image

Even a simple self closing Box causes the same issue.

image

No props on the box. I just edited a totally unrelated file (which is not even imported in any way)
Very spooky

@pixelass
Copy link
Contributor

ANd here we go again
image
image
image

@michaldudak
Copy link
Member

I haven't noticed it on my own. A repro would help us investigate this issue a lot.

@pixelass
Copy link
Contributor

After checking the OP of this thread I added fiber and drei from react-three

Check the pages/index.tsx of this repo:

https://github.com/pixelass/joy-box-repro

image

@pixelass
Copy link
Contributor

This does make sense since it is highly likely that I added react-three/fiber in the affected repositories

@pixelass
Copy link
Contributor

pixelass commented Nov 26, 2023

Seems like a simple import of react-three causes this issue (as suggested in OP extending the IntrinsicElements namespace):

image
image
image
image

@pixelass
Copy link
Contributor

pixelass commented Nov 26, 2023

Please see this discussion covering the issue: pmndrs/react-three-fiber#1752

@Hanro50
Copy link

Hanro50 commented May 17, 2024

Well ran into this issue again. Patching three fiber to make it's added IntrinsicElements elements optional fixed it for now, but I feel like fixing other packages for a bug in MUI isn't the best approach.

@pixelass
Copy link
Contributor

@Hanro50 It is actually a problem in react-three/fiber, as they are polluting the JSX namespace instead of creating their own scoped types. It offers a neat developer experience but comes with drawbacks. Also typescript is not as developed as other type systems, so we can hope that in future releases of typescript this will improve this behavior.

@R3D347HR4Y
Copy link

Thank you @pixelass @Hanro50 removing react-three/fiber from my project (wasn't using it anymore anyways) fixed my intellisense issue, now it suggests the right props for all my material components including all of the style and sx props which where starting to get bothersome
Adding some search terms so that more people can find this issue on google:
Intellisense MUI Material UI Suggestion Box

@Methuselah96
Copy link
Contributor Author

Methuselah96 commented Aug 9, 2024

@michaldudak Any chance we could fix this in MUI 6.0 by merging #38168 as a breaking change? It seems like it would be better to avoid the inconsistent behavior that currently exists as you described here.

For example, while some cases work like this one:

const StyledBox = styled(Box)(() => ({
  fontSize: "100px",
  color: "white"
}));

<StyledBox component="span" sx={{ width: 300 }} />

once you start adding props for the component in question, it stops working, like this, where the src prop errors because it doesn't know it's an image:

<StyledBox component="img" src="https://mui.com/" alt="Material UI" />

It seems like this could be a good time to rip off the band-aid and tell people to cast the result of styled(Box) to typeof Box if they want also use it with the coponent prop, which seems like it should be an edge case to begin with. This will provide the better types for everyone involved.

@michaldudak
Copy link
Member

@aarongarciah, @DiegoAndai, what do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: Box The React component. package: system Specific to @mui/system typescript
Projects
Status: Done