Define the type as a subclass of the base class using the keyword 'typeof'

If we have a base Parent class with child classes ChildA and ChildB

abstract class Parent {
    abstract foo()
}
class ChildA extends Parent {
    foo() { }
    bar() { }
}
class ChildB extends Parent {
    foo() { }
    baz() { }
}

The challenge is to create a function that can specify a parameter as any class (the actual class, not an instance) that follows the type structure of Parent, but is not specifically the class Parent itself

fn(Parent) // Should fail, this is the superclass instead of subclass
fn(new ChildA()) // should fail, this is an instance rather than the class itself
fn(new ChildB()) // should fail, this is an instance rather than the class itself
fn(ChildA) // Should succeed
fn(ChildB) // Should succeed

Answer №1

To create your own function, you can define the `fn` as shown below using a construct signature:

function fn(ctor: new (...args: any[]) => Parent) {}

This defines a constructor that generates an object which extends the `Parent` (based on structure in the type system). Interestingly, this is very similar to the example given in the documentation for abstract construct signatures.

If you attempt to pass in `Parent`, it will fail because `Parent` has an abstract constructor:

fn(Parent);
// ~~~~~~ Cannot assign an abstract constructor type to a non-abstract constructor type.

Playground


In cases where the `Parent` class is not abstract, you may want to mention a method that still works. Initially, you would need to verify if the given class is indeed `Parent` or not. Fortunately, this is achievable since types are deduced before instantiation:

function fn<Ctor extends new (...args: any[]) => Parent>(ctor: typeof Parent extends Ctor ? never : Ctor) {}

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

Extracting PNG file from response (bypassing standard JSON extraction)

Despite my efforts to find a solution, I am still unable to resolve this specific issue: I have implemented an Angular request (localhost:4200) to an API on Spring (localhost:8080). The HttpService successfully handles the requests, except when it comes to ...

Creating Dynamic Ionic Slides with Additional Slides Inserted Before and After

Hello, I am currently using ngFor to generate a set of 3 slides with the intention of starting in the middle so that I can smoothly slide left or right from the beginning. When I slide to the right, I can easily detect when the end is reached and add anot ...

The term 'MapEditServiceConfig' is being incorrectly utilized as a value in this context, even though it is meant to refer to a type

Why am I receiving an error for MapEditServiceConfig, where it refers to a type? Also, what does MapEditServiceConfig {} represent as an interface, and what is the significance of these brackets? export interface MapEditServiceConfig extends AppCredenti ...

Having trouble locating the error in my Angular and Spring Security application

I am currently working on a project that involves integrating Spring Security with an Angular client. I have encountered an issue where, despite checking for null values in the login form on the Angular side before sending it to the Java application, the J ...

Is there a way for me to store the current router in a state for later use

I am currently working on implementing conditional styling with 2 different headers. My goal is to save the current router page into a state. Here's my code snippet: const [page, setPage] = useState("black"); const data = { page, setPage, ...

Learn how to utilize the combineLatest/zip operators to only respond to emissions from the second observable while disregarding emissions from the first observable

Here's an example of how I'm initializing a property: this.currentMapObject$ = zip(this.mapObjects$, this.currentMapObjectsIndex$, (mapObjects, index) => mapObjects[index]); I want the value of this.currentMapObject$ to be emitted only ...

Remove the array stored in the local storage of an Ionic 2 application

In my application, I store data in a string. To convert the data into arrays, I use JSON.parse. this.items = JSON.parse(todos); On the results page, I display my arrays as follows: Array1 Array2 Array3 However, I have noticed that the delete button aft ...

I am encountering a TypeScript error with URLSearchParams. The object cannot be successfully converted to a string using the toString() method

During the development of my react app with postgres, express, node, and typescript, I ran into an issue while working on the backend code. The problem arises when trying to utilize URLSearchParams. index.js import express from 'express'; import ...

<Angular Command Line Interface> Implement a script within an HTML file that takes a parameter from a separate .ts file

Hey there! Sorry if it's a bit unclear, but here's the issue: I have a file called "heroes.ts" with numerous objects for a "Hero" class (exported from another file), and here is a snippet of it --> import { Hero, Villain } from '../her ...

Is it possible for Typescript and Next.js to import a different project's *source code* only from the module's root directory?

Issue with Sharing React Components between Closed and Open Source Next.js Projects I am facing a challenge in my development setup involving two Next.js projects, one closed source (Project A) and the other open source (Project B). In Project A, which is ...

Retrieve TypeScript object after successful login with Firebase

I'm struggling with the code snippet below: login = (email: string, senha: string): { nome: string, genero: string, foto: string;} => { this.fireAuth.signInWithEmailAndPassword(email, senha).then(res => { firebase.database().ref(&ap ...

How can I modify the icon once the accordion summary is expanded?

How can I switch the icon based on whether the accordion is expanded or not? I noticed that on the material ui page there is a CSS class called .Mui-expanded which can detect whether expanded={true} or false. But, how do I utilize this to change the ...

Tips for calculating the total sum of inner object property values using JavaScript, TypeScript, or Angular 5

What is the total sum of successCount values in the given array object? var successCount;//I want count of all successCount attributes from the below object var accordianData = [ { name: "Start of Day", subItemsData: [ { title: " ...

Disable the loader for a specific method that was implemented in the Interceptor

Custom Loader Interceptor A loader has been implemented within an Interceptor. I have a specific requirement where the loader should not be triggered during the upload() function. It should not be applied to that particular method only. ...

What is the process for configuring PhpStorm to sync with TypeScript tsconfig.json in .vue files?

Vue.js (webpack + vueify) with TypeScript is my current setup. The ts configuration appears to be functioning, but only in .ts files. For instance, in tsconfig.json: "compilerOptions": { "strictNullChecks": false, So strictNullChecks works as expect ...

Tips for combining values with Reactive Forms

Is there a way to merge two values into a single label using Reactive Forms without utilizing ngModel binding? <label id="identificationCode" name="identificationCode" formControlName="lb ...

Unable to access member function of Typescript class

I recently started using typescript and encountered an issue while working on a problem. I initially created the following class: export class ModuleInfoContainer extends Array<ModuleInfo> { constructor() { super(); } search(id: number) { ...

Tips for identifying `window is not defined` errors during the build process of your NextJS applications

Currently, I am in the process of transitioning an enterprise application (unable to share code) from Create React App to NextJS using TypeScript. Although I have successfully replaced React Router with Next Routes/Pages, I keep running into the same erro ...

The CLI feature is not compatible with NextJS Drizzle-Kit

I'm currently utilizing the drizzle auth template and attempting to customize it for Role Based Authentication. I've made adjustments in the db.ts file to incorporate roles. import { drizzle } from 'drizzle-orm/postgres-js'; import { pg ...

Adal TypeScript Document

Recently, I've been experimenting with the TypeScript version of adal.js. As part of my setup process, I'm referring to this link to install adal.ts. However, after executing the command: npm install adal-typescript --save a new "node_modules" ...