What is preventing the availability of those array extensions during runtime?

Looking for a simple way to work with arrays, I decided to create this custom extension class:

export class ArrayType<T extends IEntity> extends Array<T> {
  add(item: T) {
    this.push(item);
  }
  remove(item: T) {
    console.log(item);
    const index = this.findIndex(x => x.id === item.id);
    this.splice(index, 1);
  }
  update(item: T) {
    const index = this.findIndex(x => x.id === item.id);
    this.splice(index, 1, item);
  }
}

export interface IEntity {
  id: number;
}

After creating the methods, I attempted to utilize them in my Angular application as follows:

export class DepartmentListComponent implements OnInit {
  constructor(public service: DepartmentService) { }

  items: ArrayType<Department>;

  ngOnInit() {
    this.service.getAll().subscribe(x => this.items = x);
  }

  onDelete(item: Department) {
    this.items.remove(item);
    this.service.delete(item.id);
  }
  onUpdate(item: Department) {
    this.items.update(item);
    this.service.update(item.id, item);
  }
  onAdd(item: Department) {
    const id = this.service.add(item);
    item.id = id;
    this.items.add(item);
  }
}

However, I encountered a runtime error displayed at https://i.sstatic.net/VZqbn.png.

Being relatively new to TypeScript/JavaScript and Angular, I am seeking assistance in resolving this issue.

If you have any suggestions or tips on how to fix this problem, please share them. Your input is greatly appreciated!

Answer №1

Typescript doesn't automatically convert types just because you've declared the this.service.getAll() method to return a promise or observable of type ArrayType.

It seems like in your service, you may have a call to your API like this:

this._http.get<ArrayType<Department>>() 

And it appears that you're mistaken in thinking that the parameter in your subscription will be of that specific type. In reality, it's just an ordinary Array.

To address this issue, you can use the map function on your http request:

this._http.get<Array<Department>>().map(x => new ArrayType(x))

This approach requires a constructor for your ArrayType that takes an array and copies the data into the base, or you could change your class from being derived from an array to a wrapper over an array, eliminating the need to copy the data.

The reason for this difference stems from TypeScript's nature compared to languages like C# and Java. TypeScript doesn't enforce types at runtime but allows you to make assumptions about values returned from methods to help you build your code.


In order to make your ArrayType compatible with my suggestion above, you'll need the following constructor:

export class ArrayType<T extends IEntity> extends Array<T> {
    constructor(value:Array<T>){ 
        super(...value);
        Object.setPrototypeOf(this, ArrayType.prototype);
    }
//...

Since arrays are a special kind of object, the additional line in the constructor is necessary. You can refer to the TypeScript documentation for more details on this matter. Note that this feature requires TS 2.1 and may not work with IE 10 and earlier versions.

Alternatively, creating a wrapper over an array can be cumbersome, as it involves copying all the necessary array methods.

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

Automating Image Downloads with Puppeteer by Adding Authentication Query String to Image URL

Attempting to save images stored in a web-space account can be challenging. Accessing the private space with credentials and retrieving the image link using Puppeteer works smoothly. However, when the src attribute of the image includes additional authenti ...

Requirements for Method Decorators - The complete path of the class module using the decorator must be provided

Upon running the decorator (method decorators) function, we are provided with access to target, methodName, and descriptor. I am seeking the module path for target in this specific scenario. Essentially, I want the file path that points to the module that ...

The jQuery UI Dialog is experiencing an issue with a button that is triggering a HierarchyRequest

I am facing an issue with a piece of javascript that works perfectly on other pages but is now throwing a HierarchyRequestError on a new page. This leads me to believe that there may be an HTML problem on this particular page. Here is a simplified version ...

Using a function to send multiple child data in Firebase

I am trying to figure out how to save data to a Firebase multi-child node structure: --Events ----Races -------Participants Below is some dummy data example that represents the type of data I need to store in Firebase: var dummyData = [ { ...

How can I display a badge in my app when it is running using React Native?

For the past week, I've been dealing with an issue. My question is how can I display a new message badge without having to click on the message room when running my app. The badge should only show up after clicking on the message room. I see the badg ...

Iterating through a nested array in order to dynamically generate elements using JavaScript/jQuery

Seeking assistance with a specific issue I am facing. Despite extensive research on this platform, I have not found a solution to my problem. Recently, I successfully used jQuery each to loop over objects. However, I am currently struggling to iterate thro ...

Resolving Uncaught ReferenceError: require is not defined - Learn the solution here!

While working on my electron app, I encountered the error message Uncaught ReferenceError: require is not defined This is the relevant section of my code: const remote = require('electron').remote var minimise = document.getElementById('mi ...

Unit Testing Angular: Mastering Unit Testing for the .map() Function

I am in need of testing a service method, but I am unsure about how to achieve complete coverage for the code that gets executed as a result of calling another injected service method. The Service Method to be tested: @Injectable() export class BomRevisi ...

Discover the method for retrieving the upcoming song's duration with jplayer

Hey there, I have a question regarding the jPlayer music player. Currently, I am able to retrieve the duration of the current song using the following code snippet: $("#jquery_jplayer_1").data("jPlayer").status.duration; However, I now want to obtain t ...

Center-align the text in mui's textfield

What I'm looking for is this: https://i.stack.imgur.com/ny3cy.png Here's what I ended up with: https://i.stack.imgur.com/vh7Lw.png I attempted to apply the style to my input props, but unfortunately, it didn't work. Any suggestions? Than ...

The MUI classes in my React project differ between the local and live versions, creating inconsistency in styling

I've encountered a discrepancy in the Mui classes used in my React project between the local and live versions. For instance: Localhost MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-textPrimary MuiButton-sizeSmall MuiButton-textSizeSmal ...

Is there a way to incorporate an array into an array of arrays with jQuery?

I am working with an array shown below: var cString = [ ['1','Techdirt','www.techdirt.com'], ['2','Slashdot','slashdot.org'], ['3','Wired&apos ...

Updating of an Angular Directive within a nested Directive ceases once the inner Directive has been modified

Encountered a challenge with directives nested within each other in AngularJS. The issue is that both directives share the same property through a service and have an input to modify this property. The outer directive uses "transclude" to include the inner ...

Is it possible to use HTML alone in Bootstrap 5 to link a button to display a toast notification?

I'm working on a Bootstrap page that includes a button and a toast element sourced from the Bootstrap documentation. The documentation states that I need to initialize the toast in JavaScript during page load. My goal is to have the toast appear when ...

Angular: The elusive "tab" key event fails to trigger

I am facing an issue with a form field and its handler function. I need the handler to be triggered only when the user deliberately accepts the value using either the return/enter key or tabs to the next field. Using the onBlur event is not an option in th ...

Guide to testing Higher Order Components with React Testing Library

I've created a higher-order component (HOC) that adds props to a component for handling network requests and passing down data as props. Below is a simplified version of the HOC: export const withTags = (Component) => { class WithTags extends Pur ...

My function doesn't seem to be cooperating with async/await

const initialState={ isLoggedIn: false, userData: null, } function App() { const [state, setState]= useState(initialState) useEffect(()=>{ async function fetchUserData(){ await initializeUserInfo({state, setState}) // encountering an ...

Is it possible in HTML to create an "intelligent" overflow effect where text is truncated and replaced with an ellipsis "..." followed by a link to view the full content?

I have a <div> that has a limited size, and I am looking for a way to display multiline text in it. If the text exceeds the available space, I would like to add "..." at the end along with a link to view the full content on another page. Is there a ...

Having trouble with the @ngModule annotation in Angular 5? Let's find a solution

I recently integrated the selectsearchable package into my project and encountered a strange issue. Initially, everything seemed to work fine on the web and even with the ionic cordova build android command. However, when I attempted to compile the project ...

Exploring dynamic page linking with ui.router in Angular

In the process of developing a backend rails application that generates an API for consumption by a front end ionic app, I encountered an issue. Despite having experience with Angular, my familiarity with Ionic is limited. The specific problem lies in link ...