TypeScript does not detect polymorphic classes as expected

I have a class that looks like this:

export class Layer
{
    public raster: BaseRaster;

    constructor(raster: BaseRaster)
    {
       this.raster = raster;
    }  
}

In my project, I also have an abstract class named BaseRaster

export abstract class BaseRaster
{
    public doBasicStuff(): void { ... }
}

Within my project, there are multiple classes that extend the BaseRaster class. For example:

export class ValueRaster extends BaseRaster
{
   public doMoreStuff(): void { ... }
}

export class ZoneRaster extends BaseRaster
{
   public doMoreStuff(): void { ... }
}

The problem arises when I try to call a method from one of these extended classes on the Layer's raster property:

let valueRaster = new ValueRaster();
let layer = new Layer(valueRaster);

layer.raster.doMoreStuff(); // This line fails!

This is because Typescript considers layer.raster as type BaseRaster, not the specific extended class.

To work around this issue, I've had to implement type checks:

if (layer.raster.constructor.name === 'ValueRaster')
{
    (layer.raster as ValueRaster).doMoreStuff();
}
else if (layer.raster.constructor.name === 'ZoneRaster')
{
    (layer.raster as ZoneRaster).doMoreStuff();
}

While this solution works, it feels awkward and cumbersome.

Is there a way to achieve proper polymorphism in Typescript? In languages like Java, C++, or C#, calling layer.raster.doMoreStuff() would work seamlessly without the need for such type checks.

Answer №1

Uncertain about your needs, if you require a type that encompasses BaseRaster then you can specify it with a generic constraint like this...

There are some classes missing in this discussion so I have fabricated some placeholders for the sake of illustration.

class BaseRaster {
  baseRasterMethod() {
    return "hello"
  }
}

class BaseClass extends BaseRaster {}

export class Layer<T extends BaseRaster> {
    public raster: T;

    constructor(raster: T)
    {
       this.raster = raster;
    }

}

export class ValueRaster extends BaseClass
{
   public newFunction() {
     return "newFunction"
  }
}

let valueRaster = new ValueRaster();
let layer = new Layer(valueRaster);
layer.raster.newFunction // works.

Answer №2

It appears that I had an error in how I defined BaseRaster. Below is the corrected code snippet:

abstract class BaseRaster
{
    public doBasicThings(): void { ... }

    abstract public doExtraThings(): void;
}

layer.raster.doExtraThings(); // Success!

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

Docz: Utilizing Typescript definitions for props rendering beyond just interfaces

We are currently using Docz to document our type definitions. While it works well for interfaces, we've run into an issue where rendering anything other than interfaces as props in Docz components doesn't seem to display properly. I'm seeki ...

Discovering all images in Angular

I have a function that stores image data, including the name. Using *ngFor, I am able to fetch this data from the database and display it in boxes. HTML <div class="row tab-pane Galeria"> <div *ngFor="let product of products" (click)="Im ...

Technique for transferring information between properties of a class instance within an Express server's architecture

I am in the process of developing a monitoring server for a library using Express. My goal is to create different routers and routes, while also being able to access functions and variables from the monitor-server class. Currently, I have passed the ' ...

custom field component for react-hook-form

I have been working on creating a form field component that can be utilized at both the root form level and as a nested field. export type FirstNameField = { firstName: string; }; type GenericFormType<T, NS extends string | never = never> = NS ext ...

Controlling a generic interface's acceptance of certain data types in typescript: a guide

Is there a way to restrict a generic interface from accepting specific data types in TypeScript? I understand that I can define acceptable data types for a generic interface in TypeScript. interface exampleInterface<T = void | any>; But what if I w ...

Error in Nestjs Swagger: UnhandledPromiseRejectionWarning - The property `prototype` cannot be destructed from an 'undefined' or 'null' object

Currently, I am in the process of developing a Nestjs REST API project and need to integrate swagger. For reference, I followed this repository: https://github.com/nestjs/nest/tree/master/sample/11-swagger However, during the setup, I encountered the foll ...

Creating a unique tooltip component for ag-grid with the use of Material tooltips

I am facing an issue with the current angular ag-grid tooltip example, as it is not functioning properly. https://stackblitz.com/edit/angular-ag-grid-tooltip-example-fb7nko Utilizing Javascript/typescript in Angular 8 with the latest ag-grid release. I h ...

Eslint in VS Code encounters issues resolving paths within a monorepo

I'm currently working on a project with the following structure: modules │ ├── client │ ├── .eslintrc.json │ └── backend │ ├── .eslintrc.json ... One issue I've run into is that when I access the p ...

Obtain the ViewContainerRef object from the Component

Looking to create nested components in Angular 4? This is the Chooser Component import {InputComponent} from './input/input.component' import {BlockComponent} from './block/block.component' export const FormChooser = { Block: Block ...

What is preventing me from being able to use object spread results in TypeScript casting?

Uniqueness in Question My inquiry was not aimed at identifying the type or class name of an object. Rather, it delved into the concept of "casting" an object to a specific type, which arose from a misconception about TypeScript and its functionality. This ...

Managing recurring days and times in Angular and retrieving the next scheduled time

I'm currently working on a new feature that will allow users to set multiple wake alarms for specific days and times. For example, they may want alarms to go off on Mondays, Wednesdays, and Fridays at 7:00 AM and 8:00 PM, and on Tuesdays and Thursdays ...

Deduce the type of a generic class

Let's consider the following scenario: type AnyFunction = (...args: any[]) => any; abstract class Foo<F extends AnyFunction> {} class Bar extends Foo<() => string> {} In addition, there is a function like this: function foo<F e ...

Tips for adding or updating query parameters in Angular2

When navigating and updating settings in my app, I am utilizing query parameters that I need to retain and update. Adding a parameter is simple using the following method. onNavigate() { this.router.navigate(['reports'], {queryParams: {'rep ...

What is the reason for TypeScript's prioritization of arguments over assignment in generic inference?

When it comes to Typescript generics inference, the priority is given to arguments over assignment. This means that any param props are automatically converted into type unknown, even if they are assigned to a variable whose type param is set to an object ...

Adding type annotations to variables that vary in type as time progresses

In my typescript project, I have stored a stringified object in local storage. However, when attempting to retrieve the localStorage data with type annotation "string", it does not work as expected. let str : string = localStorage.getItem("userDetails"); ...

Issue: unable to establish a connection to server at localhost port 5000 while using Next.js getServerSideProps function

I am experiencing an issue with connecting to an API on localhost:5000. The API works perfectly when called from Postman or the browser, but it does not work when called inside Next.js getserverside props: mport { useEffect,useState } from "react"; i ...

Steps for passing a text parameter to a component

Struggling to develop a component for Input that requires an extra parameter in the function to receive text for the label (as shown below). Not entirely sure if this is the correct approach and unsure about how to implement it. Here's the Component ...

There was an issue with matching the call for formatting the start date to "dd MMMM yy" in the function

Hey there, while deploying my project, I encountered this error: https://i.sstatic.net/kiXLA.png Error: No overload matches this call. Overload 1 of 4, '(value: string | number | Date): Date', resulted in the following error: Argument with ...

Navigating through the directory to locate the referenced folder in a Types

Is there a way to declare a path to a referenced folder in order to have a more concise import statement using the @resources path? I am building from /server by running tsc -b app.ts The following long import statement works: import IEntity from &ap ...

Troubleshooting Issue with Chrome/chromium/Selenium Integration

Encountered an issue while attempting to build and start the application using "yarn start": ERROR:process_singleton_win.cc(465) Lock file cannot be created! Error code: 3 Discovered this error while working on a cloned electron project on a Windows x64 m ...