Create an abstract method that will return the properties of the constructor

To establish an abstract class in typescript, we can name it Entity, which contains an abstract method called constructorProps() that returns the array of properties required to build the derived class.

For instance, if Foo extends Entity and does not have a constructor, then the return type of constructorProps() should be an empty tuple:

class Entity<Child extends Entity<any>> {
  abstract constructorProps(): // What is the correct syntax here? ???
}

class Foo extends Entity<Foo> {
  override constructorProps() {
    return []
  }
}

However, suppose Bar extends Entity and has a constructor accepting one argument. In that case, constructorProps() should consistently return a [string]:


class Bar extends Entity<Bar> {
  name: string;

  constructor(name: string) {
    this.name = name;
  }
  
  override constructorProps() {
    return [this.name];
  }
}

The initial clue lies in passing the extended class as a type parameter so that the abstract class can refer to it. Despite this insight, achieving the intended outcome remains uncertain.

  • Is there a method to acquire the constructor's type (with arguments) from an instance type such as ConstructorOf<Bar>?
  • Am I taking the right approach here, or are there alternative approaches available?

Answer №1

Is it possible to retrieve the type of the constructor (including arguments) from an instance type (for example, ConstructorOf<Bar>)?

No, a an instance type does not inherently link back to its constructor. To access the type of the constructor itself, you can use typeof MyClass


If it seems like what you're looking for is:

type Constructable = { new (...args: never[]): unknown }

abstract class Entity<T extends Constructable> {
  abstract constructorProps(): Readonly<ConstructorParameters<T>>
}

In this scenario, T represents the constructor of the child class. Utilize the ConstructorParameters<T> utility type to obtain the constructor parameters.

type Constructable = { new (...args: never[]): unknown }
may seem unconventional, but it serves as a generic constructor.

Note that I included a Readonly<T> to enforce that function arguments should always be in an unchangeable tuple form. This also pairs well with as const, which will be required in the return value of constructorProps() to ensure a tuple rather than an array.


The implementation within the child class would appear as follows:

class Baz extends Entity<typeof Baz> {
  constructor(public a: number, public b: boolean) {
    super()
  }
  
  constructorProps() {
    return [this.a, this.b] as const; // using as const infers this as a tuple
  }
}

This setup functions as expected:

const baz = new Baz(123, true)
new Baz(...baz.constructorProps()) // successful operation

If approached incorrectly, you'll receive a suitable type error:

class Wrong extends Entity<typeof Wrong> {
  constructor(public a: number, public b: boolean) {
    super()
  }
  
  constructorProps() { // type error ensues
    return ['a string'] as const;
  }
}

View Playground

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

Utilizing type maps within nested objects in Typescript: A comprehensive guide

Initially, a type is established that connects enum keys with specific types: enum MyEnum { A, B } type TypeMap = { [MyEnum.A]:string, [MyEnum.B]:number } interface ObjInterface<T extends keyof TypeMap> { obj: T, objData: Ty ...

Utilizing Angular 2 or TypeScript to Retrieve Visitor's Location

I initially began using ServerVariables["HTTP_CF_IPCOUNTRY"] on the backend server, but it's proving to be too slow. I'm looking for an Angular or TypeScript alternative to speed things up. ...

It appears that Typescript mistakenly interprets a class or type as a value, indicating that "'Classname' is being referred to as a value but used as a type here."

I want to pass an Object of a React.Component as "this" to a Child React.Component in the following way: component 1 file: class Comp1 extends React.Component<...,...> { ... render() { return (<Comp2 comp1={this}/> ...

Is Angular UI's data binding more of a push or pull mechanism? How can I optimize its speed?

Suppose I have a variable a that is displayed in HTML as {{a}}. If I then update its value in TypeScript using a = "new value";, how quickly will the new value be reflected in the user interface? Is there a mechanism that periodically checks all bound var ...

Unpacking objects in Typescript

I am facing an issue with the following code. I'm not sure what is causing the error or how to fix it. The specific error message is: Type 'CookieSessionObject | null | undefined' is not assignable to type '{ token: string; refreshToken ...

Observing the World with TypeScript

Sorry, I am quite new to this and facing a bit of confusion. So, I have a CalendarService which includes a method called getYear(id: string). The structure of my Year model is as follows: export class Year { id: string; number: Number; months: ...

Creating identical class names for UL elements underneath LI using JavaScript

In my attempt to dynamically generate the class name within the ul element, I successfully achieved the expected result. The outcome can be viewed in the console of the snippet provided for reference. However, I'm facing a challenge when attempting t ...

Using a string list to define variable names or object attributes: a guide

My goal is to create an object with attributes based on a list of strings. I've come across suggestions involving dictionaries, but that doesn't seem to be the right approach for my current project. Here's a simplified version: abilities = ...

The callback function inside the .then block of a Promise.all never gets

I'm currently attempting to utilize Promise.all and map in place of the forEach loop to make the task asynchronous. All promises within the Promise.all array are executed and resolved. Here is the code snippet: loadDistances() { //return new Prom ...

Dynamic table row that expands to show additional rows sourced from various data sets

Is there a way to expand the table row in an angular-material table when it is clicked, showing multiple sets of rows in the same column as the table? The new rows should share the same column header but not necessarily come from the same data source. Whe ...

Press the text in a React Native TypeScript component to trigger a render

I am a newcomer to React Native and TypeScript, and I am struggling to figure out how to display something on the page of my app after a button is pressed. Below is the function I'm using: const getRandomNumber = () ={ const number = Math.fl ...

The BehaviorSubject will consistently emit identical values to each subscription

I am currently facing an issue with the BehaviorSubject where it emits a value for every subscription. This means that if I have, for example, 2 subscriptions to this.projectService.projectState$ streams using methods like async or tap, the projectState$ e ...

What is the best way to refresh information following its removal?

In my app, I have implemented a feature where posts are displayed as HTML cards using a component called PostList. Each card has a delete button to remove it from the list. The issue I am facing is that when I delete a card, it remains visible in the post ...

The result of comparing with `instanceof` in TypeScript

class Department { name: string; constructor(n: string) { this.name = n; } describe(this: Department){ console.log('department: ' +this.name); } } const frontend = new Department('frontend'); frontend.describe(); con ...

The node command line does not recognize the term 'require'

My Typescript project was compiling and running smoothly until recently when I started encountering the error ReferenceError: require is not defined every time I try to run node. I am uncertain whether this issue stems from Typescript, as even when I ru ...

Signatures overburdened, types united, and the call error of 'No overload matches'

Consider a TypeScript function that takes either a string or a Promise<string> as input and returns an answer of the same type. Here's an example: function trim(textOrPromise) { if (textOrPromise.then) { return textOrPromise.then(val ...

Changes in the styles of one component can impact the appearance of other

When it comes to styling my login page, I have specific stylesheets that I include in login.component.ts. For all the common CSS files, I have added them in the root index ("index.html") using the traditional method. However, after a user logs into the sys ...

Encountering a "Missing Access" error on the Discord.js API when trying to register my slash commands

Three years ago, I created a small Discord bot in Typescript that is now present on over 80 guilds. Recently, I made the decision to update it from discord.js-v12.3.1-dev to discord.js-v13.6, while also integrating the popular slash commands feature. Howe ...

Guide on integrating a plain Service/Provider into nest.js

I recently created a basic TypeScript class in nest.js called JwtTokenService.js. // JwtTokenService.js import { Injectable, Optional } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { JwtPayload } from ' ...

How can I test for equality with an array item using v-if in Vue.js?

Currently, I am facing a challenge in my Vue.js project where I need to determine if a number is equal to an element within an array. Here is the code snippet that I am working with: <div v-if="someValue != arrayElement"> // </div> I am st ...