Best practices for defining rest parameters within a named parameters class that extends a constructor in Typescript

I created a class with several parameters that are initialized in the constructor, and then I have another class that extends this one. Here is an example with simplified parameters:

class MyClass {
  name?: string;
  day?: Date;

  constructor({
    name,
    day,
  }: { name?: string, day?: Date } = {}) {
    this.name = name;
    this.day = day;
  }
}

class MySpecialClass extends MyClass {
  isSpecial?: boolean;

  constructor({
    isSpecial,
    ...options
  }: { isSpecial?: boolean } = {}) {
    super(options)
    this.isSpecial = isSpecial
  }
}

The issue here is that I haven't specified the type of options, making it hard to utilize coding suggestions and prone to errors.

const specialInstance = new MySpecialClass({ isSpecial: true, name: "sample" })
// 'name' does not exist in type '{ isSpecial?: boolean | undefined; }'

What is the correct approach to solve this problem? Rewriting all parameters manually is one solution but can lead to mistakes if some are missed.

If your solution also addresses the original MyClass by automatically extracting parameters instead of rewriting them, that would be highly beneficial.

Answer №1

One method involves defining the props as a specific type, which can then be combined with the inherited props.

For example:


type MyClassProps = { firstName?: string, birthday?: Date };

class MyClass {
  firstName?: string;
  birthday?: Date;

  constructor({
    firstName,
    birthday,
  }: MyClassProps = {}) {
    this.firstName = firstName;
    this.birthday = birthday;
  }
}

type MyCoolClassProps = MyClassProps & { isCool?: boolean }

class MyCoolClass extends MyClass {
  isCool?: boolean;

  constructor({
    isCool,
    ...props
  }: MyCoolClassProps = {}) {
    super(props)
    this.isCool = isCool
  }
}

const obj = new MyCoolClass({isCool:true, firstName:'Alice'});

See a live example in the TS Playground.

If you want to copy the types from the Constructor function, you can refer to this discussion on inheriting parameters from a parent class's constructor. However, personally, I find extracting the Types to be a simpler approach than using ConstructorParameters, as shown in this link.

I'll leave it up to others to determine which method is the most straightforward to implement and comprehend.

Answer №2

If you're looking for a way to simplify your code, consider using this helper type: https://tsplay.dev/WvyDMm

type Pure<T> = { [K in keyof T]: T[K] } & unknown
type ExtendsParameters<C extends abstract new (...args: any) => any, P> = Pure<P & NonNullable<ConstructorParameters<C>[0]>>

type x = ExtendsParameters<typeof MyClass, { isAwesome?: boolean }>
// type x = {
//     isAwesome?: boolean | undefined;
//     name?: string | undefined;
//     day?: Date | undefined;
// }

class MyAwesomeClass extends MyClass {
  isAwesome?: boolean;

  constructor({
    isAwesome,
    ...props
  }: ExtendsParameters<typeof MyClass, { isAwesome?: boolean }> = {}) {
    super(props)
    this.isAwesome = isAwesome
  }
}

This method can also be extended for multiple arguments.
If all the properties of a class match its constructor parameters, the process may become even simpler.

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

The component is unable to access VueJS references

Below is a simplified version of the code I am working with: <html> <head> <script src="file:///D:/OtherWork/javascript/vue/vue.js"></script> </head> <body> <div id="app"> & ...

Limiting jQuery datepicker to only show the selected date and disabling all others

I have two datepickers named startdate and enddate. My goal is to restrict all other dates in the enddate datepicker except the selected date from the startdate datepicker. For instance, if I choose 15/12/2016 from the startdate datepicker, I only want the ...

Learn the process of pulling information from mongoose and incorporating it into all pages

I am currently developing a basic website where users need to register and subscribe to activated challenges. I am utilizing passport for user registration, login forms, and saving user email and password in the database. However, I am facing an issue when ...

What is the best way to surround the initial x words within an element with a span tag?

Is there a way to style the first 10 words of a paragraph in a different color when the content is constantly changing? I can't manually add a span in the HTML. My approach involves using JavaScript to iterate through all instances of .overview__text. ...

Something went wrong with @wdio/runner: unable to establish session

After successfully developing cucumber tests that passed and tested some URLs with Chrome, I encountered errors when uploading to the pipeline despite the tests succeeding. Webdriver generated the following errors: INFO webdriver: DATA { 57[0-0] capabili ...

Difficulty commencing a background operation in a node.js application

I have a setup using node.js/express and React for the client side code. This setup allows users to query any number of players by making fetch requests to my express server, which then sends requests to Riot Games public API. The issue I'm encounteri ...

What is the best way to retrieve a user's country name using C#?

Currently, my code utilizes geolocation to retrieve the user's country name. Take a look at the code snippet below: navigator.geolocation.getCurrentPosition(function (pos) { var latlng = pos.coords.latitude + "," + pos.coords.longitude; var a ...

Button in HTML not functioning as expected

I have 3 different files that are crucial for my webpage to function properly: index.html: <html> <head> </head> <body> <h1>Webpage</h1> <p id = "text">Hello world!</p> <button oncl ...

When incorporating Papaparse with Angular 2, encountering the issue "Identifier 'Papa' is not found" may arise

Currently, I am facing an issue in my project where after deleting and re-installing node_modules to resolve errors, the definition of 'Papa' is missing. As a result, when npm updated the node modules again, Angular 2 is unable to find 'Papa ...

What is the best way to terminate a file upload initiated by ajaxSubmit() in jQuery?

A snippet of code I currently have is: UploadWidget.prototype.setup_form_handling = function() { var _upload_widget = this; $('form#uploader') .unbind('trigger-submit-form') // Possibly a custom method by our company . ...

Authenticate the digital signature created with the ED25519 algorithm

My current task involves verifying a digital signature that was signed using ED25519 with typescript Crypto, but I need to verify it in Java using BouncyCastle. The code snippet I am using for verification is as follows: byte[] decodedSign = Base64.getDeco ...

Using HTTP POST to subscribe and implementing a try-catch block

When using Angular2's http.post, I encountered an issue where the headers were not sent to the CORS server. To address this, I attempted to create a loop that would retry the request until it succeeds. However, this resulted in an endless loop. How ca ...

What is the origin of TrackballControls?

Seeking to enhance camera control within a threejs environment. After examining this specific demo, it appears that the functionality is largely achieved through the following lines of code: controls = new THREE.TrackballControls( camera ); controls.rota ...

Tips for sending get parameter data to a component in React

Currently, I am utilizing react (next.js) to develop a basic application. The specific issue I am facing involves creating a form in both add and edit modes. Depending on whether the get parameter contains 'edit', the form makes certain API calls ...

Guide on changing input field values based on selected radio button combinations using both AND and OR selection with JQuery

Here's the issue at hand: I have 6 sets of radio buttons, each representing a binary "yes/no" statement. In addition, there are 4 read-only input fields where I need to assign either a value of 1 or 0 based on the user's selection of radio butto ...

css effect of background image transitioning on mouse hover

Is there a way to have an element on my webpage with a background image that follows the movement of the mouse when hovered over? I want it to be similar to this website: This is the HTML code I currently have: <section id="home" data-speed="3" data-t ...

Unable to display nested JSON data from API in Vue.js

Having trouble accessing nested properties from API JSON data. The Vue component I'm working on: var profileComponent = { data : function() { return { isError : false, loading : true, users : null, ...

Tips on retrieving and sending an XML string in PHP to JavaScript using MySQL

Here is the code snippet I have: <input type='button' value='clickme' onclick='download(\"\" . $rowtable['Protocolo'] . \".xml\", \"\" . $rowtable['XML&a ...

Converting Javascript Variables into a PHP Script

After noticing that the same question was being asked repeatedly, I delved into thorough research to discover effective methods for transferring a couple of JavaScript variables to a PHP script. Include data in a form as hidden values Send to URL, like & ...

What is the method to fetch the index and remove an element from an object in angular 8?

I've been attempting to remove an element from an object, but for some reason it's not getting deleted. The format of my object is as follows: {"UNDET":0,"HLDS":8,"NGS":2,"NGRT":1,"TotalCount":13,"NGX":1} What I'm looking to do now is del ...