Expanding Arrays in TypeScript for a particular type

There is a method to extend arrays for any type:

declare global {
  interface Array<T> {
    remove(elem: T): Array<T>;
  }
}

if (!Array.prototype.remove) {
  Array.prototype.remove = function<T>(this: T[], elem: T): T[] {
    return this.filter(e => e !== elem);
  }
}

Source: Extending Array in TypeScript

But now the question arises, is it possible to extend the array only for a specific type?. For example, only for arrays of type User -> Array<User>.

I aim to introduce an extension method, like .toUsersMap(), which will only be accessible for arrays containing items of type User.

Answer №1

You can replicate similar functionality:

type Person = {
  tag: 'Person'
}

interface Array<T> {
  toPeopleMap: T extends Person ? (elem: T) => Array<T> : never
}

declare var person: Person;

const personsArr = [person]

personsArr.toPeopleMap(person) // valid

const someOtherArray = [{ notPerson: true }]

someOtherArray.toPeopleMap() // Cannot call this expression

If the T parameter does not extend the Person type, TypeScript will prevent using the toPeopleMap method.

Try it out here

Answer №2

Suppressing the IntelliSense prompting for toUsersMap() on Arrays may not be feasible, but you can enforce a compiler error when calling arr.toUsersMap() unless arr is of type Array<User>. One method to achieve this is by incorporating a this parameter in the toUsersMap() method:

interface Array<T> {
  toUsersMap(this: Array<User>): Map<string, User>;
}

Now, the compiler will mandate that toUsersMap() can only be invoked with a this context referring to something assignable to Array<User>:

interface User {
  username: string;
}
const arr = [{ username: "foo" }, { username: "bar" }];
arr.toUsersMap() // No error, works fine

const another_array = ["hello", 123];
another_array.toUsersMap() // Error occurs
//~~~~~~~~~~~ <--
// The 'this' context of type '{ notUser: boolean; }[]' is 
// not compatible with the method's 'this' of type 'User[]'

Link to Playground with code

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

Achieving top-tier efficiency in segmenting items within an array of objects

Looking for a way to decrease the size of an array directly on my NodeJS server's memory. I aim to optimize network traffic by sending only the essential 'header' details of each object within the array. The current array on the server look ...

Using TypeORM with a timestamp type column set to default null can lead to an endless loop of migrations being

In my NestJs project using TypeORM, I have the following column definition in an entity: @CreateDateColumn({ nullable: true, type: 'timestamp', default: () => 'NULL', }) public succeededAt?: Date; A migration is gene ...

Middleware for Redux in Typescript

Converting a JavaScript-written React app to Typescript has been quite the challenge for me. The error messages are complex and difficult to decipher, especially when trying to create a simple middleware. I've spent about 5 hours trying to solve an er ...

Ensure the Json object contains an integer

I am facing an issue where I receive a Json data in dictionary format. Below is a sample json: Receivedtext: { "x": "pricef", "b": "usd", "ds": [ "tpr", "avgp", "mcap", "ppc7D", "ppc12h", "ppc4h", "ppc24h" ], "data": ...

Updating directives is required when there is a modification in the input

I created a custom directive that controls the opacity of an element based on an input value: import { Directive, ElementRef, HostListener, Input, OnInit } from '@angular/core'; import { Observable, Subscription } from 'rxjs/Rx'; @Dir ...

Wrapper around union function in TypeScript with generics

I'm struggling to find a solution for typing a wrapper function. My goal is to enhance a form control's onChange callback by adding a console.log. Can someone please point out what I might be overlooking? interface TextInput { type: 'Tex ...

How does one distinguish between the uses of "any" and "any[ ]"?

Exploring the Difference Between any and any[ ] An Illustrative Example (Functioning as Expected) variable1: any; variable2: any[]; this.variable1 = this.variable2; Another Example (Also Functioning as Intended) variable1: any; v ...

Utilize the <wbr> tag within FormattedMessage and assign it as a value while coding with TypeScript

Trying out the optional word break tag <wbr> in a message within <FormattedMessage id="some:message" />. Context Some words or texts are too lengthy for certain parent elements on smaller mobile screens, and we have a column layout t ...

Error encountered during Jasmine unit testing for the ng-redux @select directive

Here is a snippet from my component.ts file: import { Component, OnInit } from '@angular/core'; import { select } from 'ng2-redux'; import { Observable } from 'rxjs/Observable'; import { PersonalDetailsComponent } from ' ...

Sharing API data between components in Angular 5

Summary: I'm trying to retrieve data from an input field in a component form, then compare it using API services. After that, I want to take the value from the "correo" field in the form and pass it to another component. In this other component, I aim ...

Sending an event from a child component to another using parent component in Angular

My form consists of two parts: a fixed part with the Save Button and a modular part on top without a submit button. I have my own save button for performing multiple tasks before submitting the form, including emitting an Event to inform another component ...

What are some ways to make autorun compatible with runInAction in mobx?

Currently delving into the world of mobx and runInAction, facing a challenge in comprehending why autorun fails to trigger my callback in this particular scenario: class ExampleClass { // constructor() { // this.exampleMethod(); // } ...

Is it feasible to use a component in a recursively manner?

Following a two-hour search for a solution, I decided to reach out to experts as I suspected the answer might be simpler than expected. The project in question is an Angular7 one. In my goals component, I aim to include a "goal" with a button labeled "+". ...

Unable to create a loop within the constructor to assign API values

I created an export type shown below: export type Program{ key: string; value: string; } An array of values is returned from the API like this: apival = ["abc", "xyz" ...etc] In my component's constructor, I am implementing the f ...

Wondering how to implement HubSpot Conversations SDK in a Typescript/Angular application?

Recently, I came across some useful javascript code on this website window.HubSpotConversations.widget.load(); window.HubSpotConversations.widget.refresh(); window.HubSpotConversations.widget.open(); window.HubSpotConversations.widget.close(); Now, I am l ...

Retrieving JSON array data in Android via a URL getPath

I am new to Android app development and currently working on an app that displays information about items in the game Guild Wars 2. You can find the data here. My goal is to read the entire list of items including their name, price, and icon, and display t ...

Update the value in a nested object array by cross-referencing it with a second nested object array and inserting the object into the specified

I have a large array of objects with over 10,000 records. Each object contains an array in a specific key value, which needs to be iterated and compared with another array of objects. If there is a match, I want to replace that value with the corresponding ...

How can I save a TypeScript object to Firebase using serialization?

Having an issue: Within my angular application, I have implemented a lot of classes with inheritance. However, upon attempting to save these objects to Firebase, I encountered an error indicating that I am trying to persist custom objects which is not supp ...

React Typescript Context state isn't refreshing properly

Struggling to modify my context state, I feel like I'm overlooking something as I've worked with context in the past. The challenge lies in changing the 'isOpen' property within the context. You can view my code here: CodeSand **app.ts ...

Identifying the absence of a character at the end of the last line in Node.js to detect

Currently, I am processing data line by line from a buffer. Within the buffer, the data is structured as follows: name,email,phn test1,<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="47332234337607223f262a372b226924282a">[em ...