npm and TypeScript

Installing from npm and Adding TypeScript Types

The manual recommends npm 2,036 with a bundler, Vite 25,978 in its examples: npm install three, then npx vite. The package is ES modules only (require('three') now prints a deprecation warning), and its exports map adds three/addons/*, three/webgpu and three/tsl. It ships no .d.ts files; add @types/three (github.com/three-types/three-ts-types (https://github.com/three-types/three-ts-types 301 )) with the same minor number, and TypeScript 7.0.2's tsc --noEmit catches misuse before the browser does:

main.ts: two mistakes the type definitions catchTypeScript
import * as THREE from 'three';
const book = new THREE.Mesh(new THREE.BoxGeometry(0.42, 0.98, 0.12),
  new THREE.MeshStandardMaterial({ color: '#1f5f8b' }));
book.position.set(0, '0.5', 0);          // a string where a number belongs
book.material.roughnes = 0.6;            // a misspelled property
Output
main.ts(4,22): error TS2345: Argument of type 'string' is not assignable to parameter of type
  'number'.
main.ts(5,15): error TS2551: Property 'roughnes' does not exist on type
  'MeshStandardMaterial'. Did you mean 'roughness'?

Plain JavaScript runs both lines silently: the string reaches the world matrix, and a later position.y += 0.1 makes the height '0.50.1'.

The silent bug TypeScript would catch: a string position makes a book vanishHTMLLive
<!doctype html>
<style>
  body { margin: 0; background: #f5f1e8; font: 13px system-ui, sans-serif; color: #263238; }
  canvas { display: block; max-width: 100%; }
  pre { margin: 6px 8px; font-size: 12px; background: #fff; padding: 6px; border-left: 4px solid #b5452f; max-width: 570px; white-space: pre-wrap; }
</style>
<script type="importmap">
{ "imports": {
  "three": "https://cdn.jsdelivr.net/npm/three@0.186.1/build/three.module.js",
  "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.186.1/examples/jsm/" } }
</script>
<pre id="log"></pre>
<script type="module">
import * as THREE from 'three';

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(600, 260);
document.body.prepend(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color('#f5f1e8');
const camera = new THREE.PerspectiveCamera(35, 600 / 260, 0.1, 50);
camera.position.set(0, 0.5, 3.4);
camera.lookAt(0, 0.4, 0);
scene.add(new THREE.HemisphereLight('#ffffff', '#8d6e63', 1.2));
const sun = new THREE.DirectionalLight('#ffffff', 2.5);
sun.position.set(2, 3, 4);
scene.add(sun);

const makeBook = (color, x) => {
  const book = new THREE.Mesh(new THREE.BoxGeometry(0.42, 0.98, 0.12),
    new THREE.MeshStandardMaterial({ color }));
  book.position.x = x;
  scene.add(book);
  return book;
};
const good = makeBook('#1f5f8b', -0.5);
const bad = makeBook('#b5452f', 0.5);

good.position.set(-0.5, 0.5, 0);
bad.position.set(0.5, '0.5', 0);        // a string where a number belongs: JavaScript accepts it
bad.material.roughnes = 0.6;            // a misspelled property: silently ignored

// Lift both books by 0.1 m: for the string, += concatenates text
good.position.y += 0.1;
bad.position.y += 0.1;

const log = document.getElementById('log');
log.textContent =
  `blue: position.y = ${good.position.y} (${typeof good.position.y})\n` +
  `red:  position.y = '${bad.position.y}' (${typeof bad.position.y}) → matrix NaN, book not drawn\n\n` +
  `tsc --noEmit with @types/three would report:\n` +
  `  error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.\n` +
  `  error TS2551: Property 'roughnes' does not exist on type 'MeshStandardMaterial'. Did you mean 'roughness'?`;

// A marker where the red book should be
const ghost = new THREE.Mesh(new THREE.BoxGeometry(0.42, 0.98, 0.12),
  new THREE.MeshBasicMaterial({ color: '#b5452f', wireframe: true }));
ghost.position.set(0.5, 0.6, 0);
scene.add(ghost);

renderer.setAnimationLoop((time) => {
  good.rotation.y = ghost.rotation.y = Math.sin(time / 900) * 0.5;
  renderer.render(scene, camera);
});
</script>