What is the best way to utilize ThreeJS ES6 native modules alongside Typescript?

I have been experimenting with using ThreeJS ES6 native modules directly in the browser. It's quite exciting to be able to import ThreeJS right into my javascript files without needing a module bundler.

In javascript, it works like this:

import * as THREE from './lib/three.module.js'
import { OrbitControls } from './lib/OrbitControls.js'

Now, I am attempting to achieve the same thing in Typescript. I installed the typescript definitions using

npm install --save @types/three 

However, even after that, VS Code is still unable to locate the type declaration files:

⚠️ Could not find a declaration file for module '../lib/three.module.js'

⚠️  Could not find a declaration file for module '../lib/OrbitControls.js'.

After following suggestions from comments, I modified the imports to:

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

Although the declarations can now be found, Typescript is still having trouble locating the modules!

⚠️  An accessor cannot be declared in an ambient context and Failed to resolve module specifier "three". 

⚠️  Relative references must start with either "/", "./", or "../".

I am left wondering how I can effectively use ES6 native modules from ThreeJs in my Typescript project without resorting to a module bundler?

Answer №1

Consider arranging your imports in the following manner:

import * as React from 'react'
import { useState } from 'react';

Answer №2

To ensure TypeScript recognizes the shape of a library module, you'll need to create a .d.ts file with matching name, such as ./lib/three.module.d.ts. When you use

import * as Three from "./lib/three.module.js"
, TypeScript automatically searches for a corresponding typings file using its module resolution strategy. In this declaration file, you can simply define and export types that accurately reflect the structure of the module. For your situation, a simple solution could be:

import * as Three from "three";
export = Three;

Answer №3

Jamesernator shared an alternative solution in the TypeScript Github Issues. Simply include this code snippet in your HTML:

<script type="importmap">
            {
                "imports": {
                    "three": "./js/lib/three.module.js"
                 }
            }    
 </script>

This will allow the browser to handle the remapping process automatically. Pretty neat!

Check out more details here.

Answer №4

It appears that using an alias for declaration files is necessary, as aliases are not compatible with es6 native import statements. Unfortunately, this issue is not mentioned in the documentation: https://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html

Some individuals address this problem by implementing a comprehensive build pipeline solution, but I opted for a less complex approach: Typescript declaration file created with alias instead of relative path

Instead, I utilized tsc-watch and crafted a simple bash script: https://www.npmjs.com/package/tsc-watch

$ tsc-watch --onSuccess "./mysed"

$ cat ./mysed
#!/bin/bash

# use *js to capture .mts as well as .js
sed -i "" "s/import \* as THREE from 'three';/import \* as THREE from '.\/lib\/three\.module\.js';/" js/*js;

This script replaces import * as THREE from 'three'; in my .ts with

import * as THREE from './lib/three.module.js'
in my JS code, enabling me to utilize the typed version during development and the non-typed version in production. Phew!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Troubleshooting the inclusion of nodemon in package.json

I am interested in implementing nodemon to automatically recompile the project when there are changes made to the code during development. package.json { "name": "insurance-web-site", "version": "0.1.0", " ...

Enhance React components in Deck.GL by including default properties for each child component

I am currently working on a customizable collection of map layers using Deck.GL & React. I have developed a BaseMap component through which I will be passing data layers as react children. This is the current implementation: BaseMap: export const BaseMap ...

Is it possible that using npm link could be the root cause of the "module not

As I delve into understanding how to utilize TypeScript modules in plain JavaScript projects, it appears that I am facing a limitation when it comes to using npm linked modules. Specifically, I can successfully use a module that is npm-linked, such as &apo ...

Unlock the Power of Angular: Leveraging ViewEncapsulation.Native to Access HTML Elements

I am encountering an issue where I am receiving an error when trying to access an HTML element by ID. The problem arises when I attempt to access the classList upon a user clicking a button to apply a different style class to the element. The class list an ...

Enhancing TypeScript builtin objects in Netbeans using a custom plugin

While in the process of converting JavaScript code to TypeScript, I encountered a challenge with extending built-in objects using Object.defineProperty, such as String.prototype. Object.defineProperty(String.prototype, 'testFunc', { value: funct ...

Is there a way to reset static data in a TypeScript subclass? (or alternative method for managing global data)

I have a particular set of static data that I would like to access through an API using basic logic. Specifically, this data pertains to metadata about Java classes. My approach involved incorporating the API into a few static methods within a class, alon ...

Navigating an array and organizing items based on matching properties

When I receive an array that looks like this: errors = [ { "row": 1, "key": "volume", "errorType": "Data type", "expectedType": "number", &quo ...

Utilizing Vue 3's Inject Plugin alongside the powerful Composition API and TypeScript

I developed a controller plugin to be used globally in all components, but I am facing challenges making it compatible with Vue 3 + TypeScript + Composition API as I keep getting a TypeScript error. ui/plugins/controllers.ts import { App } from 'vue& ...

Leverage the power of data binding in Typescript Ionic by exposing object functions

Is there a way to execute a function on a Typescript model object within an Ionic HTML template? Whenever I try to do so, it triggers an error message saying self.context.$implicit.myFunctionName is not a function. In my Ionic2 app, I am aiming to showcas ...

What causes objects to intersect in A-Frame even when they are seemingly distanced from each other?

My charts appear in front of a globe object in A-Frame, but when I move the camera in the scene, the order of objects changes causing the charts to overlap and become invisible. I'm unsure of the cause and how to fix it. Here are some screenshots of t ...

Update the router URL without switching pages, yet still record it in the browser history

One of the features on my search page allows users to perform searches and view results. Initially, I faced a challenge in updating the router URL without navigating, but I managed to overcome this by utilizing the "Location" feature. In my ngOnInit meth ...

I encountered an issue where TypeScript's generics function was unable to locate a property within an interface

I am attempting to define a function in typescript using generics, but I encountered the following error: "Property 'id' does not exist on type 'CustomerInterface'" This occurs at: customer.id === +id getCustomer<Custo ...

Customizable parameters in a React component

I am encountering two issues with the code provided below: interface MyForm { age: number; email: string; name: string; } function Form< T, ComponentProps extends { name: string; onChange: (event: React.ChangeEvent) => void; } &g ...

Welcome to the awe-inspiring universe of Typescript, where the harmonious combination of

I have a question that may seem basic, but I need some guidance. So I have this element in my HTML template: <a href=# data-bind="click: $parent.test">«</a> And in my Typescript file, I have the following code: public test() { alert( ...

Using Angular with Google Maps: Learn how to retrieve a list of markers from a map and implement onClick events for each one

I am currently using the AGM angular module for Angular 2+ to integrate the Google Map API. In my project, I have a directive that displays waypoints as markers on the map using the Google Map Directions Service. Now, I am looking for a way to handle the ...

Learn how to use Angular2 or TypeScript to display 'unsubscribe' and 'subscribe' text on a toggle button

I'm working on a toggle button that initially displays the word subscribe on the thumb. When the toggle is disabled, I want it to show unsubscribe instead. Can someone please help me achieve this functionality? Here's the code snippet: <md-s ...

Experiencing an issue with mui/material grid causing errors

An error occurred in the file Grid2.js within node_modules/@mui/material/Unstable_Grid2. The export 'createGrid' (imported as 'createGrid2') could not be found in '@mui/system/Unstable_Grid' as the module has no exports. Desp ...

Updating the geometry of an object while the camera is in motion can result in visual errors in the three.js library

I am currently facing an issue with updating a vertex of a line in my three.js project. My goal is to create a line within my scene where one end is fixed at (0,0,0) and the other end is set to a specific position on the user's screen (x,y coordinate ...

Is it possible to obtain the URL (including parameters) of the first navigation before proceeding with the navigation process?

My goal is to automatically navigate to a specific website when a certain condition for the URL is met. Consider the following scenario in the ngOnInit() method of app.component.ts: if (urlMatchesCondition()) { await this.router.navigateByUrl('sp ...

Can you explain the distinction between 'rxjs/operators' and 'rxjs/internal/operators'?

When working on an Angular project, I often need to import functionalities like the Observable or switchMap operator. In such cases, there are two options available: import { switchMap } from 'rxjs/operators'; or import { switchMap } from ' ...