渲染
Box
会产生以下错误:
表达式产生的联合类型太复杂而无法表示.ts(2590)
正如我在here所看到的,这是因为同时安装了
@mui/material
和@react-three/drei
&@react-three/fiber
。
此错误背后的原因是什么?我只从
Box
导入 mui
组件。是否存在类型混淆或其他问题?解决方案/解决方法是什么?
重现步骤:
npx create-react-app my-app --template typescript
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"
},
npm install
Typescript v4.4.4
src
。我把它命名为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;
App.tsx
并添加来自 Box
的 @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;
注意 请尝试在
VSCode
或您首选的编辑器中本地重现此错误。例如,我没能在 codesandbox
上重现这一点。我不知道为什么没有出现该问题。我怀疑这是因为他们使用了不同的打字稿版本。
更新
我在 MUI 和 React-3 上都提出了问题:
Select TypeScript version command
。帖子来源:FreePhoenix888。
原答案:这里
虽然我确信在某些情况下可能会出现此问题,但现在发生在我身上的原因是
npm
安装了 @chakra-ui/system
的重复版本,它定义了 forwardRef()
的类型声明.
当我跑步时
npm ls @chakra-ui/system
我可以看到我同时拥有@chakra-ui/[email protected]
和@chakra-ui/[email protected]
。
@chakra-ui/[email protected]
)定义了 1.9.0
的确切版本 @chakra-ui/system
,而大多数包(例如 @chakra-ui/[email protected]
)将非常开放的 >=1.0.0
定义为 peerDependencies
。从 npm v7 开始,npm 默认安装 peerDependencies
。
这似乎会导致 npm 为开放的 >=1.0.0
安装
最新版本,然后分别安装特定的
1.9.0
,并且不够智能来删除重复数据。
我可以通过以下任一方式解决这个问题
rm package-lock.json && npm install --legacy-peer-deps
。然而,这对 npm 安装的软件包有很大影响。
或者,将
overrides
(需要 npm >=8.3
)添加到 package.json
以指定要安装的特定版本。
"overrides": {
"@chakra-ui/system": "1.9.1"
}
您可能需要在再次运行安装之前删除它来重新生成
package-lock.json
,以实际强制执行此新解决方案。
这将仅确保对特定包进行重复数据删除,而不是像“--legacy-peer-deps”那样更改其他不相关的包。
我在使用
next@14
项目和以下依赖项构建 typescript@5
时遇到了此错误:
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@mui/material": "^5.15.9",
"@react-three/drei": "^9.96.5",
"@react-three/fiber": "^8.15.15",
"three": "^0.160.1",
错误可以通过“
Box
per Box
”来解决,帮助打字稿理解组件的通用性:
<Box
component={'div'} <<< this got rid of the error
sx={{
position: 'fixed',
top: 2,
left: 2,
zIndex: 1,
}}
>
...
进一步调试后,我将打字稿版本升级到最新的稳定标签:
5.3.3
。这解决了全局错误。