Guide on TypeScript child classes: defining argument and return types for methods inherited from parent classes

I am facing a scenario where I have a parent class that mandates child classes to implement a unique businesslogic() method. Each child class has its own version of the businesslogic() method with different type signatures.

The parent class includes a common method that relies on the implementation of the child's businesslogic() method.

This code snippet illustrates the situation:

abstract class Parent {
  protected name: string;

  constructor(name: string) {
    this.name = name;
  }

  protected abstract businesslogic(params?: unknown): unknown;

  public setup(params?: unknown): unknown {
    // code logic involving `params`
    const result = this.businesslogic(params);
    // process the outcome of the business logic
    console.log(result);
    // return the result
    return result;
  }
}

class Child1 extends Parent {
  businesslogic(c: number): number {
    return c + 1;
  }
}

class Child2 extends Parent {
  businesslogic(c: string): string {
    return c;
  }
}

const firstChild = new Child1("Mirco");
firstChild.setup(1);

const secondChild = new Child2("Isolde");
secondChild.setup("a");

In this instance, each child class defines a custom businesslogic() method with varying type signatures.

When using tsc, it seems to interpret firstChild.setup(1) based on the general signature

Parent.setup(params?: unknown): unknown
-- which functions correctly. However, I am seeking an improved approach where I can somehow "override" the type signature of setup(params?: unknown): unknown within the child class declaration to enforce stricter type constraints when invoking a child's setup() method.

Essentially, I aim to modify the type signature of the common method in the parent class within the child class declaration. Is there a way to achieve this?

I welcome suggestions for more elegant solutions to tackle this issue!

Answer №1

There are various ways to structure and define these connections, and one approach utilizes generics and TypeScript 4's new variadic tuple types. By specifying the function parameters and return type as generic types within the Parent class, you can ensure type safety.

If incorrect parameter types are passed to the setup method or an attempt is made to assign its return value to a different type, compilation will fail.

abstract class Parent<T extends unknown[], U> {
  protected name: string;

  constructor(name: string) {
    this.name = name;
  }

  protected abstract businesslogic(...params: [...T]): U;

  public setup(...params: [...T]): U {
    // perform business logic using `params`
    const result = this.businesslogic(...params);
    // process the result of the business logic
    console.log(result);
    // then return it
    return result;
  }
}

class Child1 extends Parent<[number], number> {
  businesslogic(num: number): number {
    return num + 1;
  }
}

class Child2 extends Parent<[string], string> {
  businesslogic(str: string): string {
    return str;
  }
}

class Child3 extends Parent<[number, string], string> {
  businesslogic(num: number, str: string): string {
    return num + 1 + str;
  }
}

class Child4 extends Parent<[], string> {
  businesslogic(): string {
    return "";
  }
}

const child1 = new Child1("Alice");
// result1 is a number
const result1 = child1.setup(1);

const child2 = new Child2("Bob");
// result2 is a string
const result2 = child2.setup("c");

const child3 = new Child3("Charlie");
// Child3 requires 2 parameters for setup
// result3 is a string
const result3 = child3.setup(1, "c");

const child4 = new Child4("David");
// Child4 does not require any parameters for setup
const result4 = child4.setup();

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

Ways to conceal table rows depending on their content

I am currently developing a project using Angular 2. One of the features includes a summary section that consolidates all the data from other sections. The summary is presented in a table format, with each row displaying the field name in the first colum ...

Utilize Angular 6 to Enhance Open Street Maps by Adding a Custom Marker to the Map

After reading through this article, I have successfully developed an OSM layer component. My next goal is to incorporate a pin or marker for a specific geo-location. Has anyone else achieved this task before? ...

Decipher the splitButton tag from PrimeNG

I am currently attempting to translate items from "p-splitButton", but I am facing a challenge because the "items" is an object. How can I accomplish this task? [model]="items | translate" app.component.html <p-splitButton label="Save" icon="pi pi- ...

The FormGroup Matrix in Angular 2+

Looking to develop an interface for creating a matrix, which requires two inputs for width and height. The matrix of inputs will vary based on these dimensions. I'm facing a challenge in making these inputs unique so they can be correctly associated ...

To handle a 400 error in the server side of a NextJS application, we can detect when it

I'm facing a situation where I have set up a server-side route /auth/refresh to handle token refreshing. The process involves sending a Post request from the NextJS client side with the current token, which is then searched for on the server. If the t ...

Refactoring TypeScript components in Angular

How can I streamline the TypeScript in this component to avoid repeating code for each coverage line? This angular component utilizes an ngFor in the HTML template, displaying a different "GroupsView" based on the context. <div *ngFor="let benefitG ...

An effective approach to positioning HTML elements at specific X and Y coordinates

I have an innovative project idea! The concept is to enable users to create points by clicking on the display. They can then connect these points by clicking again. However, I am facing a challenge when it comes to creating HTML elements at the exact loc ...

Error occurred while trying to implement style due to unsupported MIME type ('text/html') for the stylesheet

I am encountering multiple errors while attempting to access my application: Encountered errors while trying to load the application:</p> <pre><code>Refused to apply style from 'http://localhost:8000/styles.2466d75470f9c2227ee1.css&a ...

Setting an expiry date for Firestore documents

Is it feasible to set a future date and time in a firestore document and trigger a function when that deadline is reached? Let's say, today I create a document and specify a date for the published field to be set to false fifteen days later. Can this ...

I have attempted numerous methods, but the TypeScript object remains potentially undefined

My current code involves using canvas to capture the cropped image. Below is the function that handles this process: export const getCroppedImg = ( image: HTMLImageElement, crop: Crop, fileName: string ): Promise<Blob> => { let canvas: HTM ...

Typescript fails to recognize that props are passed by react-navigation through withNavigation HOC

I am encountering an issue with a specific package setup: "react-navigation": "2.18.2", "@types/react-navigation": "2.13.0", "typescript": "3.1.6", The problem arises when attempting to utilize the withNavigation higher-order component in a child compone ...

What is the reason behind TypeScript's concern over a missing property in generic inheritance?

Exploring a test case with TypeScript: interface BaseFoo {} interface FooAdapter { method<F extends BaseFoo>(foo:F):string; } interface ConcreteFoo extends BaseFoo { value:string; } class ConcreteFooAdapter implements FooAdapter { method(fo ...

Creation of source map for Ionic 2 TypeScript not successful

Struggling with debugging my Ionic 2 application and in need of guidance on how to include souceMap for each typescript file that corresponds to the javascript files. Despite enabling "sourceMap":true in my tsconfig.json file, the dev tools in Chrome do n ...

Leveraging MathJax within a Typescript/Angular2 component

Struggling with calling the MathJax.Hub functions in my angular2 component. Spent hours trying to figure it out last night. Need to use the MathJax API to re-render dynamically bound InnerHTML string. However, unable to access the MathJax global variable ...

A guide to finding the mean in Angular by utilizing JSON information

import { Component, OnInit } from "@angular/core"; import { MarkService } from "../app/services/marks.service"; @Component({ selector: "app-root", templateUrl: "./app.component.html", styleUrls: ["./app.component.scss"] }) export class AppComp ...

Containerizing Next.js with TypeScript

Attempting to create a Docker Image of my Nextjs frontend (React) application for production, but encountering issues with TypeScript integration. Here is the Dockerfile: FROM node:14-alpine3.14 as deps RUN apk add --no-cache tini ENTRYPOINT ["/sbin ...

What is the reason behind TypeScript rejecting the syntax of checkbox input elements?

When trying to use the following checkbox in TypeScript, I encountered a warning: <input type="checkbox" onClick={(event: React.MouseEvent<HTMLInputElement>) => { setIsTOSAccepted(event.target.checked); }} defaultChecked={ ...

A method for increasing a counter using only an instance of a class or function without accessing its methods or properties in Javascript

Looking at the task ahead, let increment = new Increment(); I have been tasked with creating a Javascript class or function called Increment in order to achieve the following: console.log(`${increment}`) // should output 1 console.log(`${increment}`); ...

Deliver either a Promise or a boolean based on the provided parameters, utilizing a default

I have some code that can either return a boolean or a Promise depending on the parameters provided. function setGuid<B extends boolean>(guid: string, shouldValidate?: B): B extends true ? boolean : Promise<boolean> function setGuid(guid: strin ...

Strange behavior of the .hasOwnProperty method

When attempting to instantiate Typescript objects from JSON data received over HTTP, I began considering using the for..in loop along with .hasOwnProperty(): class User { private name: string; private age: number; constructor(data: JSON) { ...