TypeScript
You may want to use TypeScript when developing your React Three Fiber applications.
TypeScript is a tool that you can use when developing, to help you make sure all your code is type safe. I.e., if you need to pass an integer to a function, but you write it as a string instead, then the TypeScript compiler will notify you while developing.
Using TypeScript is optional, and many syntax issues can already be found if using ESLint as described at ESLint.
Using TypeScript in a React application requires some extra considerations since types are not automatically inferred when using some hooks, such as the useRef hook.
So to follow this small tutorial, use the courses Leva
branch.
git clone https://github.com/Sean-Bradley/React-Three-Fiber-Boilerplate.git
cd React-Three-Fiber-Boilerplate
git checkout leva
npm install
npm start
Later, you can experiment with a copy of your own project, provided that you are using react-scripts
or R3F-pack to build it.
Install Latest R3F-Pack
Note
If your project is already using R3F-pack, then you can skip this next step.
Ensure that your project is using the latest R3F-pack bundler and not react-scripts
In your own project, check the start
and build
commands in your package.json
→ scripts
node to see which one.
If it is using react-scripts
, then uninstall it.
npm uninstall react-scripts
Next, install the latest R3F-Pack
npm install r3f-pack@latest --save-dev
And make sure your package.json
→ scripts
node is using the r3f-pack
command and not react-scripts
{
...
"scripts": {
- "start": "react-scripts start",
+ "start": "r3f-pack start",
- "build": "react-scripts build",
+ "build": "r3f-pack build"
},
...
}
Rename file extensions from jsx
to tsx
Rename files with the jsx
extension, to use the tsx
extension.
App.jsx --> App.tsx
index.jsx --> index.tsx
Polyhedron.jsx --> Polyhedron.tsx
The files may now show some errors and warnings when viewed in the IDE. We will fix those.
Install TypeScript
Press Ctrl C a few times to stop the development web server and execute,
npm install typescript --save-dev
Add a tsconfig.json
Add a tsconfig.json
to your projects root folder.
Copy/paste the contents below into it and save.
{
"include": ["./src/**/*"],
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"lib": ["dom", "es2015"],
"jsx": "react-jsx"
}
}
Install Type Definitions
The IDE will read your code and try to match the types to it. You can tell it which definition files to use.
npm install @types/node --save-dev
npm install @types/react --save-dev
npm install @types/react-dom --save-dev
npm install @types/three --save-dev
After installing type definitions, it can take some time for the IDE to catch up. Try pressing F1, and select Restart TS Server
.
Also note that you should try to match the versions of the types with the library installed.
E.g., If you are using Three@0.157.0
then install the closest @types/three
version such as,
npm install @types/three@0.157.0 --save-dev
Note
Since the type definitions are developed separately from the main library, the latest version numbers won't always be in sync. Just try to match the closest number that you can, and you may not experience any issues unless you are using some part of the library where the method signature was recently changed.
Add types to index.tsx
In index.tsx
, the IDE is unsure what type is being returned from the document.getElementById
method. We can cast the type as a HTMLDivElement
.
Change the createRoot
line from,
createRoot(document.getElementById('root')).render(
to
createRoot(document.getElementById('root') as HTMLDivElement).render(
When working with TypeScript, you often need to figure out the correct type of variable, or the value a method returns.
Sometimes you might get stuck trying to figure out the best type to use. In that case, you can cast as any
.
createRoot(document.getElementById('root') as any).render(
Or, you can add the directive // @ts-ignore
before the line containing the error.
// @ts-ignore
createRoot(document.getElementById('root')).render(
Add types to Polyhedron.tsx
There are several problems in this file, lets look at Binding element 'polyhedron' implicitly has an 'any' type
The Polyhedron function is using destructuring assignment and a rest (...) operator.
Since when creating the Polyhedron, which is based on a THREE.Mesh
, but with some extra custom attributes, I have chosen to create an interface named IPolyhedron
which extends from the R3F MeshProps
since the function returns a <mesh>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Also, since there is a useRef
hook pointing to a mesh
JSX element, I have declared it as,
const ref = useRef<THREE.Mesh>(null!)
Also, I needed to cast color as THREE.Color
to avoid a problem in App.tsx
where it passed the value as a string, and Leva could pass as a color, but the JSX in Polyhedron.tsx
requires it to be a THREE.Color
.
// line 20 App.tsx
color: {
value: 'lime'
}
// line 6 Polyhedron.tsx either THREE.Color or String
color: THREE.Color | String
// line 27 Polyhedron.tsx
<meshBasicMaterial color={color as THREE.Color} wireframe />
npm start
All problems should now be solved, we can run,
npm start
Working Example
Useful links
Leva (TypeScript version) | sbedit.net | GitHub |
Materials (TypeScript version) | sbedit.net | GitHub |
GLTFJSX (TypeScript version) | sbedit.net | GitHub |
Using with TypeScript | Pmdrns.docs |
GitHub Branches
These 3 branches below show some variation in how I solved adding Types to the code.
leva-typescript
git clone https://github.com/Sean-Bradley/React-Three-Fiber-Boilerplate.git
cd React-Three-Fiber-Boilerplate
git checkout leva-typescript
npm install
npm start
materials-typescript
git clone https://github.com/Sean-Bradley/React-Three-Fiber-Boilerplate.git
cd React-Three-Fiber-Boilerplate
git checkout materials-typescript
npm install
npm start
useGLTF-typescript
git clone https://github.com/Sean-Bradley/React-Three-Fiber-Boilerplate.git
cd React-Three-Fiber-Boilerplate
git checkout useGLTF-typescript
npm install
npm start
Troubleshooting
Error 'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.
Ensure you have a tsconfig.json
and that you have installed the type definitions for both React
and React-dom
.
npm install @types/react --save-dev
npm install @types/react-dom --save-dev
If using VSCode, then you can press F1 and select Restart TS Server
to re-scan the type definitions.
Error : TypeError: THREE.Vector3 is not a constructor
I have seen this error when using react-scripts@5.0.1
with typescript@4.x.x
and @react-three/drei
.
Upgrade your package.json
to reference the latest TypeScript.
npm install typescript@latest --save-dev
Now you have a choice here to instead upgrade your project to use R3F-pack, or you can continue to use react-scripts
to start
and build
your project.
If you choose to continue to use react-scripts
, then you will need to add an overrides
section to your package.json
that matches the version of TypeScript that was just installed.
// ... existing package.json
"typescript": "^5.1.3"
},
"overrides": {
"typescript": "^5.1.3"
}
}
Error : npm ERR! While resolving: react-scripts@5.0.1
When executing npm install
you see the error,
npm install
npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR!
npm ERR! While resolving: react-scripts@5.0.1
npm ERR! Found: typescript@5.x.x
You are using react-scripts
and have TypeScript 5 or above installed, but not yet added the overrides
node to your package.json
See TypeError: THREE.Vector3 is not a constructor