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:
- Setup a cra app:
npx create-react-app my-app --template typescript
- 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"
},
- Run
npm install
- Make sure you're running on
Typescript v4.4.4
- Add the following component to your
src
. I name itThreeRenderer.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;
- Go to
App.tsx
and add aBox
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;
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: