How to override or redefine a TypeScript class with generics

Presently, I am immersed in a project involving three.js and TypeScript. It has come to my attention that for organizing elements, the Group class is highly recommended. However, I have noticed that the type definitions for Group do not include a feature like this:

meshGroup = new Group<Mesh>() 

where the meshGroup.children property is exclusively comprised of Meshes.

My attempt was to create a custom type like this:

declare class MeshGroup extends Group {
  children: Mesh[]
  add(...object: Mesh[]): this
}

meshGroup = new MeshGroup() 

Unfortunately, I encountered this console error:

_classes_MeshGroup__WEBPACK_IMPORTED_MODULE_16__.MeshGroup is not a constructor

I searched for a simple way to implement such a wrapper in TypeScript, but without success.

Another approach I considered was to implement a typed array like this:

meshGroup: Mesh[] = []

and maintain synchronization with the class to manage the types, but this adds another layer of complexity.

As I am not an expert in TypeScript, I am wondering if there is a quick type definition trick to implement this "wrapper" definition?

Answer №1

When utilizing the group.children method, an array of Object3D[] is returned according to the definition file. This is because a Group can potentially contain various elements such as

Group, Sprite, Line, Point, Mesh, etc.
, hence it defaults to the generic Object3D. However, if it is known that the group will only consist of Mesh objects, it can be explicitly cast as follows:

const group: THREE.Group = new THREE.Group();
const children = group.children as THREE.Mesh[];

// This allows access to Mesh attributes, for example
const mat = children[0].material;

Answer №2

UPDATE

One way to enhance the Group class and make it more type-safe is by extending it with a specialized class and utilizing the parent functions (known as the decorator pattern):


import { Group } from 'three'
import { Object3D } from 'three/src/core/Object3D'

export default class TypedGroup<T extends Object3D = Object3D> extends Group {
  children: T[] = []

  add(...object: T[]) {
    return super.add(...object)
  }

  remove(...object: T[]): this {
    return super.remove(...object)
  }

  attach(object: T): this {
    return super.attach(object)
  }

  getObjectById(id: number): T | undefined {
    return super.getObjectById(id) as T | undefined
  }

  getObjectByName(name: string): T | undefined {
    return super.getObjectByName(name) as T | undefined
  }

  getObjectByProperty(name: string, value: string): T | undefined {
    return super.getObjectByProperty(name, value) as T | undefined
  }
}

original solution

Thank you for the input @Marquizzo!

That could definitely serve as a viable solution. Another approach I considered was modifying the package through patch-package and editing the Group.d.ts file in this manner:

export class Group<T extends Object3D = Object3D> extends Object3D {
    constructor();
    type: 'Group';
    readonly isGroup: true;
    children: T[];
    add(...object: T[]): this;
    remove(...object: T[]): this;
    attach(object: T): this;
    getObjectById(id: number): T | undefined;
    getObjectByName(name: string): T | undefined;
    getObjectByProperty(name: string, value: string): T | undefined;
}

Incorporating your suggestion, I was also able to achieve type safety on the methods, which was a crucial aspect for me!

While I'm uncertain if this approach will be optimal in the long run, it currently addresses my need for type consistency :D

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

Error message: The object is not visible due to the removal of .shading in THREE.MeshPhongMaterial by three-mtl-loader

Yesterday I posted a question on StackOverflow about an issue with my code (Uncaught TypeError: THREE.MTLLoader is not a constructor 2.0). Initially, I thought I had solved the problem but now new questions have surfaced: Even though I have installed &apo ...

What is the best way to tally up the occurrences of a specific class within an Angular application?

After reviewing the resources provided below on impure and pure pipes in Angular applications: What is impure pipe in Angular? I have been curious about inspecting the instances created by an Angular application firsthand, although I am uncertain if thi ...

When compiling my TypeScript file, I encountered an error stating that a block-scoped variable cannot be redeclared

In my Visual Studio Code, I have written just one line of code in my ex1.ts file: let n: number = 10; Upon compiling using the command tsc ex1.ts, the compiler successfully generates the ex1.js file. However, VSC promptly displays an error in the .ts file ...

The FBXLoader encountered an issue locating the version number within the fbx file

I am encountering an issue while attempting to load a .fbx file. The loader.load function is throwing the following error message: "THREE.FBXLoader: Cannot find the version number for the file provided." Unfortunately, I am unsure of how to resolve this p ...

Using TypeScript with Vue to Retrieve Information from a Form

Currently, I am attempting to retrieve data from a form in Vue using TypeScript. However, when declaring the data that I intend to use with this form, it seems to be posted on the fields as shown in this screenshot: message getting posted. I am unsure ho ...

What is the best way to switch from using the three.js JSONLoader to the ObjectLoader?

I successfully loaded multiple files using the code below for three.js JSONLoader: <!DOCTYPE html> <html> <head> <title>Rotating Sphere</title> <meta charset="utf-8"> <!-- https://cdnjs.com/libra ...

Limit the frequency of function calls in Typescript

Update: After some research, I've learned that throttle has the capability to drop excess function invocations, making it unsuitable for my needs. I am still seeking an idiomatic solution to process every item in a queue at an appropriate pace without ...

Guide on extracting the id from the path parameter in an HTTP request using Cloud Functions and nodejs

I am currently in the process of developing a serverless application using GCP Cloud Functions (nodejs). I have successfully implemented different behaviors based on the request method, but I am facing an issue with retrieving the id from the path paramete ...

Tips for applying a texture to only one side of a cube without using THREE.MultiMaterial to lower draw calls

Imagine a scenario where there is a cube featuring 2 different materials. While I am utilizing MultiMaterial, I have noticed that it results in 6 draw calls instead of just 2. This concerns me in terms of performance, especially if the project is scaled up ...

Modify a particular attribute in an array of objects

I am currently working on an Angular project and dealing with the following array object: { "DATA": [ { "CUSTOM1": [ { "value": "Item1", ...

Discover the power of catching Custom DOM Events in Angular

When working with an Angular library, I encountered a situation where a component within the library dispatches CustomEvents using code like the following: const domEvent = new CustomEvent('unselect', { bubbles: true }); this.elementRef.nati ...

Customizing the main color scheme in Naive-UI with typescript

I am a beginner with Naive and I want to change the primary color of my app theme to orange. Initially, I used vuestic for this purpose but now I am struggling to implement it. Below is my main.ts file where I had the vuestic override (commented out). Ca ...

Is it possible to leverage TypeScript type support in Electron by incorporating require statements within functions or conditions?

The Electron Performance documentation advises against loading and running code too soon. It suggests using the strategy of deferring the loading of sizable modules until they are actually needed, rather than placing all require() statements at the top of ...

I am having difficulty accessing the values stored in my cardTiles variable

I am facing an issue with a variable called cardTiles in my Angular 9 component. The variable is defined as cardTitles:Product[] = []; The Product class is defined as follows export class Product{ productName: string;} When I console.log(this.cardTi ...

Tips on invoking Bootstrap's collapse function without using JQuery

We are facing a challenge with our TypeScript files as we have no access to jQuery from them. Our goal is to trigger Bootstrap's collapse method... $(object).collapse(method) but without relying on jQuery. Intended Outcome //Replicates the functio ...

How to retrieve Angular directive name using TypeScript

I have successfully implemented the following AngularJS directive: export module Directives { export class PasswordsMatch implements ng.IDirective { public static Factory(name: string) : ng.IDirectiveFactory { return () => new ...

What is the best way to show the previous month along with the year?

I need help with manipulating a date in my code. I have stored the date Nov. 1, 2020 in the variable fiscalYearStart and want to output Oct. 2020. However, when I wrote a function to achieve this, I encountered an error message: ERROR TypeError: fiscalYear ...

Combine Sonarqube coverage with Istanbuljs/NYC for enhanced code analysis

In my typescript project, we utilize a Jenkins pipeline to run all functional tests in parallel after building the main container. Towards the end of the pipeline, we conduct a code coverage check and then transfer the results to sonarqube. Below is an ex ...

Form validation is an essential feature of the Angular2 template-driven sub form component

I'm currently working on a template-driven form that includes a group of inputs generated through an ngFor. My goal is to separate this repeating 'sub-group' into its own child component. However, I'm encountering difficulties in ensur ...

The name 'BrowseAnimationModule' cannot be located

Can someone help me figure out how to install or fix this import issue I'm having with the 'animations' directory in @angular/platform-browser/animations not importing properly? import {CommonModule} from '@angular/common'; import ...