6

Rendering a Box produces the following error:

Expression produces a union type that is too complex to represent.ts(2590)

As I can see here, this is due to having both @mui/material and @react-three/drei & @react-three/fiber installed.

What is the reasoning behind this error? I'm only importing the Box component from mui. Is there a type mixup or something? What would be the solution/workaround?

Steps to reproduce:

  1. Setup a cra app: npx create-react-app my-app --template typescript
  2. Add the following packages to your package.json
  "dependencies": {
    "@azure/msal-browser": "^2.18.0",
    "@azure/msal-react": "^1.1.0",
    "@emotion/react": "^11.5.0",
    "@emotion/styled": "^11.3.0",
    "@mui/icons-material": "^5.0.4",
    "@mui/lab": "^5.0.0-alpha.51",
    "@mui/material": "^5.0.4",
    "@mui/system": "^5.0.4",
    "@react-three/drei": "^7.16.8",
    "@react-three/fiber": "^7.0.17",
    "axios": "^0.23.0",
    "dotenv": "^10.0.0",
    "localforage": "^1.10.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router": "^5.2.1",
    "react-router-dom": "^5.3.0",
    "react-scripts": "4.0.3",
    "three": "^0.133.1",
    "three-stdlib": "^2.5.4",
    "web-vitals": "^1.1.2",
    "zustand": "^3.5.14"
  },
  "devDependencies": {
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^11.2.7",
    "@testing-library/user-event": "^12.8.3",
    "@types/jest": "^26.0.24",
    "@types/node": "^12.20.33",
    "@types/react": "^17.0.30",
    "@types/react-dom": "^17.0.9",
    "@types/react-router-dom": "^5.3.1",
    "@types/three": "^0.133.1",
    "@typescript-eslint/eslint-plugin": "^4.29.3",
    "@typescript-eslint/parser": "^4.29.3",
    "cross-env": "^7.0.3",
    "eslint-config-airbnb": "^18.2.1",
    "eslint-config-airbnb-typescript": "^14.0.1",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-import": "^2.25.2",
    "eslint-plugin-jsx-a11y": "^6.4.1",
    "eslint-plugin-react": "^7.26.1",
    "eslint-plugin-react-hooks": "^4.2.0",
    "jest-when": "^3.4.1",
    "rimraf": "^3.0.2",
    "typescript": "^4.4.4"
  },
  1. Run npm install
  2. Make sure you're running on Typescript v4.4.4
  3. Add the following component to your src. I name it ThreeRenderer.tsx:
import { Html, OrbitControls, PerspectiveCamera, useGLTF, useProgress } from '@react-three/drei';
import { Canvas, useFrame } from '@react-three/fiber';
import { FC, Suspense, useEffect, useRef, useState } from 'react';
import { AnimationAction, AnimationMixer } from 'three';
import { GLTF, GLTFLoader } from 'three-stdlib';
import create from 'zustand';
import { devtools } from 'zustand/middleware';

export const useGLTFModel = create<{ readonly model: () => GLTF | undefined }>(
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  devtools((set) => ({
    model: () => undefined
  }))
);

export const useGLTFAnimationAction = create<{ readonly animationAction: () => AnimationAction[] | undefined }>(
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  devtools((set) => ({
    animationAction: () => undefined
  }))
);

interface ModelProps {
  readonly gltfPath: string;
  readonly onLoad: () => void;
}

const Model: FC<ModelProps> = ({ gltfPath, onLoad }) => {
  const model = useGLTF(gltfPath, undefined, undefined, (loader: GLTFLoader) => {
    loader.manager.onLoad = onLoad;
  });

  // Refs
  const rootRef = useRef();
  const animationActionsRef = useRef<AnimationAction[]>();

  // Mixer
  const [mixer] = useState(() => new AnimationMixer(model.scene));
  useFrame((_state, delta) => mixer.update(delta));

  // Effects
  useEffect(() => {
    useGLTFModel.setState({ model: () => model });

    animationActionsRef.current = model.animations.map((animation) => mixer.clipAction(animation, rootRef.current));
    useGLTFAnimationAction.setState({ animationAction: () => animationActionsRef.current });

    return () => {
      model.animations.map((animation) => mixer.uncacheClip(animation));
    };
  }, [model, mixer]);

  return <primitive ref={rootRef.current} object={model.scene} />;
};

const Progress = () => {
  const { progress } = useProgress();
  return (
    <Html center>
      <span style={{ color: 'white' }}>{progress}% loaded</span>
    </Html>
  );
};

const ThreeRenderer: FC<ModelProps> = ({ gltfPath, onLoad }): JSX.Element => {
  const cameraRef = useRef();

  return (
    <Canvas>
      <PerspectiveCamera ref={cameraRef} position={[0, 5, 5]} />
      <OrbitControls camera={cameraRef.current} />
      <ambientLight intensity={0.5} />
      <Suspense fallback={<Progress />}>
        {/* <Environment preset="city" /> */}
        <Model gltfPath={gltfPath} onLoad={onLoad} />
      </Suspense>
    </Canvas>
  );
};

export default ThreeRenderer;

  1. Go to App.tsx and add a Box component from @mui/material.
import React from 'react';
import logo from './logo.svg';
import './App.css';
import {Box} from '@mui/material';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
        <Box>

        </Box>
      </header>
    </div>
  );
}

export default App;

  1. You should see the error appear. What I see: enter image description here

NOTE Please try to reproduce this error locally in VSCode or your preferred editor. I did not manage to reproduce this on codesandbox for example. I don't know why there the issue does not appear. I suspect that's because they use a different typescript version.

UPDATE

I've opened issues on both MUI and react-three:

Vivere
  • 1,919
  • 4
  • 16
  • 35
  • 1
    Can you add your code here? – NearHuscarl Oct 19 '21 at 06:23
  • @NearHuscarl I added the packages as well as a picture. – Vivere Oct 19 '21 at 06:56
  • I can't see what's wrong [here](https://codesandbox.io/s/boxsx-material-demo-forked-9tl5q?file=/demo.tsx) – NearHuscarl Oct 19 '21 at 07:03
  • I don't understand, then what's going on in my local sandbox. – Vivere Oct 19 '21 at 07:05
  • Check if your project uses workspace's typescript version. – zilijonas Oct 19 '21 at 07:11
  • @zilijonas I'm using vscode and I configured it to use the version from my node modules, the error still shows up. – Vivere Oct 19 '21 at 07:20
  • 1
    I found it, so after I install `@react-three/fiber` then it breaks – Vivere Oct 19 '21 at 08:05
  • @Vivere wasn't it mentioned in the original question you linked? but I suppose you need that package. – NearHuscarl Oct 19 '21 at 12:02
  • Yup, I need it. I created an issue on their GitHub page and I hope I get some guidance. It is really really strange and I don't have any leads on why this is occuring. – Vivere Oct 19 '21 at 12:09
  • @NearHuscarl I finally managed to reproduce it on two different PCs in multiple sandboxes. But I did not manage to reproduce it in `codesandbox.io`. Can you look at the updated post and let me know if this issue appears on your side as well? – Vivere Oct 20 '21 at 06:29
  • 1
    [codsandbox](https://codesandbox.io/s/boxcomponent-material-demo-forked-ot73s?file=/demo.tsx). Sorry, I don't have time to install and test on local. You should file an issue on MUI repo, someone on there probably can help you. – NearHuscarl Oct 20 '21 at 07:49
  • I did, for both `mui` and `fiber` repos. Hopefully they will help me with some workarounds. – Vivere Oct 20 '21 at 07:54
  • Maybe this is related to typescript because 4.4.4 was just released recently? Try downgrading it to see if it helps. – NearHuscarl Oct 20 '21 at 11:41
  • @Vivere did you ever get to the bottom of this? I've been trying different things for hours. Like you, I was using `@react-three/fiber` and uninstalling fixes the error but I need R3F. – ChrisCrossCrash Sep 29 '22 at 00:39
  • 1
    @ChrisCrossCrash adding a `component="div"` to Box fixes it. See my latest update where I posted links to issues opened against both repositories. Follow those links for more info on the matter. – Vivere Oct 04 '22 at 20:47

2 Answers2

7
  1. Open a JavaScript or TypeScript file in VS Code.
  2. In the VS Code command palette, run the TypeScript: Select TypeScript version command.
  3. Make sure you have Use workspace version selected.

Post Credits: FreePhoenix888.

Original Answer: Here

4

While I'm sure there are several situations where this problem can occur, the reason why this was happening to me right now was that npm was, installing a duplicated version of @chakra-ui/system which defines the type declartion of forwardRef().

When I ran npm ls @chakra-ui/system I could see that I had both @chakra-ui/system@1.9.1 and @chakra-ui/system@1.9.0.

This is likely because some dependencies, like @chakra-ui/skeleton@1.2.4 defines an exact version 1.9.0 of @chakra-ui/system, while most packages, like @chakra-ui/menu@1.8.3, defines a very open >=1.0.0 as a peerDependencies. Since npm v7, npm installs peerDependencies by default.

It seems like this can result in npm installing the latest version for the open >=1.0.0 and then the specific 1.9.0 separately and not be intelligent enough to dedupe it.

I could work around this by either

  • rm package-lock.json && npm install --legacy-peer-deps. This has a lot of affects on what packages npm installs however.

  • or, add an overrides (requires npm >=8.3)to the package.json to specify a specific version to install.

    "overrides": {
         "@chakra-ui/system": "1.9.1"
     }
    

    You might have to regenerate the package-lock.json by deleting it before running install again to actually force this new resolution.

    This will only make sure to dedupe the specific package and not change other, unrelated packages like ´--legacy-peer-deps` does.

oBusk
  • 852
  • 2
  • 10
  • 21