The creation of a fresh child instance in Typescript using rest parameters

My goal is to create a parent class that allows children to generate new instances of the same child type. When I specify the number of parameters, everything functions correctly:

abstract class AClass {

  protected sameTypeWithSingle (
    x: any
  ): this {
    const self = this as this & {
      constructor: { new (x: any) }
    }
    return new self.constructor (x)
  }

  protected sameTypeWithDouble (
    a: any, b: any
  ): this {
    const self = this as this & {
      constructor: { new (a: any, b: any) }
    }
    return new self.constructor (a, b)
  }
}

However, when I attempt to accept any number of parameters in order to match any child constructor signature, it does not work (shown with TypeScript error comments):

abstract class AClass {

  protected sameTypeWith (
    ...args: any[]
  ): this {
    const self = this as this & {
      constructor: { new (...args: any[]) }
    }
    return new self.constructor (...args)
    // [ts] Cannot use 'new' with an expression whose type
    // lacks a call or construct signature.
  }
}

I am puzzled as to why it breaks - it works with 2 parameters but not with any? Is there a way to achieve my intended functionality?

Thank you for your help,

Seb

Answer №1

This situation seems rather peculiar in my opinion. It appears that self.constructor is categorized as type

Function & (new (...args: any[]) => any)
, which one would assume should be newable. However, there seems to be some kind of hindrance within the compiler causing an issue, possibly due to some specific handling of new (...args: any[]) that is inadvertently affecting this situation. If time allows, I may attempt to investigate further or possibly submit a report on GitHub, although I cannot guarantee it at this moment.

UPDATE: According to @MattMcCutchen's comment, it seems like this problem was already brought up as a known bug some time ago. Additionally, he apparently made a pull request to address it (well done!), so hopefully this issue will be resolved in TypeScript 3.2.


In terms of a workaround, you can achieve your desired outcome by making the following adjustment:

abstract class AClass {
  protected sameTypeWith(
    ...args: any[]
  ): this {
    const self = this as this & {
      constructor: { new(arg0?: any, ...args: any[]): any } // modification here
    };
    return new self.constructor(...args); // this solution works
  }
}

When having an optional first argument of type any followed by a rest parameter of type any[], it should be equivalent to just using a rest parameter of any[]. However, it appears that they do not function in the same way. Hopefully, this explanation sheds some light on the matter. Best of luck!

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

Unable to access or modify properties within a function passed as an argument

deleteDialog(item, func: Function) { this.dialogService .open(ConfirmDialogComponent, { context: { title:"Are you sure?", cancelClss: "info", confirmClss: "danger", }, ...

The InMemoryCache feature of Apollo quietly discards data associated with fragments that are declared on the main

After sending the following query to my GraphQL server: fragment B on root_query { foo { id } } query A { ...B } The data received from the server includes the foo field. However, when I retrieve it using Apollo's InMemoryCache a ...

Transforming an array of flat data into a hierarchical tree structure

I'm facing a challenge with my script. I have an Array of FlatObj and some rules, and I need to create a converter function that transforms them into TreeObj. The Rules are: If an object has a higher depth, it should be a child of an object with a l ...

Is it possible to execute TestCafe tests using TypeScript page objects that have not been utilized?

While working with TestCafe, I am implementing tests using the Page Objects pattern. I have already written some page objects in advance, even before their actual usage, as I am familiar with the page and know what to anticipate. However, when attempting ...

Tips for excluding test files in next.js when building

I am currently developing a next.js application with tests integrated within the page directory structure. In order to achieve this, I have made necessary configurations in the next.config.js file. const { i18n } = require('./next-i18next.config' ...

Component in Angular2 encountering a null value

Unexpected situations may arise where "this" becomes null within a component. So far, I have encountered it in two scenarios: 1) When the promise is rejected: if (this.valForm.valid) { this.userService.login(value).then(result => { ...

Exploring TypeScript: Understanding how to define Object types with variable properties names

Having an issue with a React + TypeScript challenge that isn't causing my app to crash, but I still want to resolve this lingering doubt! It's more of a query than a problem! My goal is to set the property names of an object dynamically using va ...

Ways to establish the relationship between two fields within an object

These are the definitions for two basic types: type AudioData = { rate: number; codec: string; duration: number; }; type VideoData = { width: number; height: number; codec: string; duration: number; }; Next, I need to create a MediaInfo typ ...

Exploring the Differences between Angular's Http Module and the Fetch API

While I grasp the process Angular uses for HTTP requests, I find myself leaning towards utilizing the Fetch API instead. It eliminates the need to subscribe and unsubscribe just for a single request, making it more straightforward. When I integrated it int ...

Tips for sending data to CSS in Angular

I have an Angular application where I need to calculate the width of an element and store it in a variable called finalposition. Then, I want to move this element to the left by (finalposition)px when hovering over it. How can I achieve this styling effect ...

Utilizing Enum Lowercase as Index Key Type in TypeScript

Is there a way in TypeScript to use the lower case of an enum as an index key type? I have an enum defined as: export enum NameSet { Taxi = 'Taxi', Bus = 'Bus', Empty = '', } I want to define an object with keys based o ...

What makes FC function components stand out from traditional vanilla React function components?

I recently came across this FC function component: const LabelForm: FC<LabelFormProps> = ({ labels, selectedID, }) => { const selectedLabel = selectedID !== undefined && labels[selectedID]; In my usual implementation, I do it like t ...

Disruptions in typing occur due to errors popping up while utilizing zod and react-hook-forms within a TypeScript application

Currently, I am working on developing a registration page for users using react-hook-forms for the registration form and zod for validation. Initially, when testing the form, I noticed that errors only appeared after submitting the form. However, once the ...

What is the best way to ensure a specific row remains at the bottom of an Angular table with Material when sorting?

My data table contains a list of items with a row at the end showing the totals. | name | value1 | value2 | --------------------------- | Emily | 3 | 5 | | Finn | 4 | 6 | | Grace | 1 | 3 | | TOTAL | 8 | 14 | I&apos ...

I'm having trouble locating a declaration file for the module 'vue-prism-component'

Currently utilizing Vue 3 (Composition API), Vite, and Typescript but encountering a missing module issue with vue-prism-component. <script lang="ts" setup> import 'prismjs' import 'prismjs/themes/prism-tomorrow.css' imp ...

What is the optimal method for navigating through a complex nested object in Angular?

Looking to navigate through a nested object structure called purchase. Within this structure, there is a sub-array named purchaseProducts which contains another sub-array called products along with additional data. What methods do you suggest for efficien ...

The successful conversion of Typescript to a number is no longer effective

Just the other day, I was successfully converting strings to numbers with no issues. However, today things have taken a turn for the worse. Even after committing my changes thinking all was well, I now find that when attempting to cast in different ways, I ...

When initialized within an object, Angular may identify a field as undefined

Whenever I attempt to access a property of the object named "User," it shows up as undefined. However, upon logging the complete object to the console, the field appears with the necessary data. Here is the console log output: perfil.component.ts:42 unde ...

Issues with utilizing destructuring on props within React JS storybooks

I seem to be encountering an issue with destructuring my props in the context of writing a storybook for a story. It feels like there may be a mistake in my approach to destructuring. Below is the code snippet for my component: export function WrapTitle({ ...

"Running into Memory Limitations: Resolving System.OutOfMemoryException in ASP.NET Web API Integrated with Angular

Currently, I am working on integrating Angular 2+ with asp.net Web API. The issue I am facing is related to dealing with a C# DataTable that is being returned to Angular 2+. To do this, I am utilizing the Post method. The problem arises when I try to retr ...