Creating a factory method within a parent class to generate instances of child classes

I am in the process of implementing a generic factory method on my base class that can create instances of any of the descendant classes, without the base class being aware of all the descendants. My current approach generates functional JS code, but...

  • Even though I have used ///<reference>, I am encountering a TS warning (see code): Property 'Base' does not exist on type 'typeof MyNS'
  • The Typescript documentation contains numerous cautions against enclosing modules within namespaces.
  • This method seems to only function properly when the files are merged into a single outFile due to how the classes are linked to exports (refer to gist at the end). While this is acceptable, I am interested in exploring an alternative that does not have this limitation.

Base.ts:

export namespace MyNS {
    export abstract class Base {
        static create(foo) {
            return new MyNS[foo.type]();
        }
    }
}

Descendant.ts:

/// <reference path="Base.ts" />
export namespace MyNS {
    // Property 'Base' does not exist on type 'typeof MyNS':
    export class Descendant extends MyNS.Base {
        echo(s: string) {
            return s;
        }
    }
}

Generated JS code: https://gist.github.com/zbjornson/2053cf1a30e893f38f7910dcada712d2

Is there a more effective way to expose the descendant classes to the base?

Answer №1

(Here is one approach using decorators, though I am open to other solutions as well.)

To achieve this, we can utilize decorators in the following way:

Base.ts:

var descendants = {};
export abstract class Base {
    static create(foo) {
        return new descendants[foo.type](foo);
    }

    static Descendant(constructor: Function) {
        descendants[constructor.name] = constructor;
    }
}

Descendant.ts:

import { Base } from "./Base.ts";

@Base.Descendant
export class Descendant extends Base {
    echo(s: string) {
        return s;
    }
}

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

Leverage Async Await for Setting Response Data in TypeScript

Currently, I am making multiple API requests with different data and storing all the responses in an array. Then, I am using .map to map the response array to my original array to update the data. However, it seems like the process is not working correctly ...

Tips for bypassing arrow functions when sending prop values to another component?

**Stateful ApplicatorType Component** class ApplicatorType extends Component { public state = { applicatorTypes: ['Carpenter', 'Painter', 'Plumber'], applicatorTypesSelected: [], } public render() { allotedTypes = ( &l ...

Tips on using Visual Studio Code to troubleshoot Angular 4 unit tests

I am working on an Angular 4 project with Material design in Visual Studio Code. The setup is done using angular/cli. Currently, I have been writing unit tests using Karma and Jasmine. However, when trying to debug the tests by setting breakpoints, it doe ...

What could be causing TypeScript to identify my immer draft as undefined?

I'm completely lost, can someone please help me with this issue: Currently, I am trying to update a typed configuration. Within my Provider component: const [data, setData] = useImmer<typeof INITIAL_CONFIG>(INITIAL_CONFIG) ... function updateF ...

Is the tooltip display for Typescript types in VSCode reliable? No need for unnecessary type assertions

Exploring the concept of const assertions in TypeScript Looking at the array allDeviceTypes depicted below, VSCode indicates it has a return type of string[] when hovering over the variable name. https://i.sstatic.net/gIYch.png However, upon using a con ...

The pairing of Transpiller and Internet Explorer 8 is like a dynamic

In starting my new project, I am considering using BabelJS. However, there is a significant requirement that must be met: it needs to be compatible with IE8. ISSUE: Babel compiles ES6 to ES5, but the support for ES5 on IE8 is lacking. Are there any alter ...

"Encountering a TypeScript error when using React Query's useInfiniteQuery

I am currently utilizing the pokeApi in combination with axios to retrieve data import axios from 'axios' export const fetchPokemonData = async ({ pageParam = "https://pokeapi.co/api/v2/pokemon?offset=0&limit=20" }) => { try ...

Navigating json data in angular 6

I retrieved a JSON object in the following format response = [ { 'a': [ { 'b': [ { 'c': [ { 'name': 'abc', 'value': 900 ...

The function service.foo is not recognized in Angular

My service function is not being recognized by my component import { Injectable } from '@angular/core'; import { ToastController } from '@ionic/angular'; @Injectable({ providedIn: 'root' }) export class LocationService { ...

Using Angular 6 to Format Dates

Can anyone provide instructions on how to achieve the following format in Angular? Expected: 20JAN2019 Currently, with the default Angular pipe, I am getting: 20/01/2019 when using {{slotEndDate | date:'dd/MM/yyyy'}} Do I need to write a ...

Link the ngModel input to an object within an ngFor iteration

Looking to create a dynamic form using an array that includes FieldLabel and DataModel references. I want to use the DataModel as an object reference, so when the user updates an input field, the referenced model is updated. I have searched extensively bu ...

Tips for utilizing JSON in a TypeScript file within a Node.js environment

I have been working on implementing JSON type in my Node.js application, but I am encountering some data in a scripted format. Here is the response: }, data: '\x1F\b\x00\x00\x00\x00\x00\x00\x00]PMo0\f ...

Data retrieval from DynamoDB DocumentClient does not occur following a put operation

I am currently working on testing a lambda function using the serverless framework in conjunction with the sls offline command. The purpose of this lambda is to connect to my local DynamoDB, which has been initialized with a docker-compose image, and inser ...

Angular 14 is throwing an error due to an indent issue - the expected indentation is 2 spaces but 4 spaces were found

Currently using "eslint": "^8.23.0" with angular 14. Everything was functioning properly with "eslint": "^8.22.0", but after updating to 8.23.0, I encountered the following error: https://i.sstatic.net/UALvS.png ...

The struggle of accessing child components using ViewChild in Angular

I am facing an issue with a dialog box that is supposed to display a child component separately. Below is the code for the child component: @Component({ selector: 'userEdit', templateUrl: './edituser.component.html', styleUrls: [ ...

Conceal a designated column within a material angular data table based on the condition of a variable

In the morning, I have a question about working with data tables and API consumption. I need to hide a specific column in the table based on a variable value obtained during authentication. Can you suggest a method to achieve this? Here is a snippet of my ...

What is the process of defining a callback function in Typescript?

Here is a function that I am working with: .add({a: 1, b: 2}, function (msg, reply) { reply({z: msg.z}) }) I attempted something like this: interface SenecaMethods { add: (pattern: object, CALLBACK NEEDS TO BE INSERTED HERE) => object; } ...

The inclusion of a custom list preview with prepare in the sanity schema results in errors during the construction

I recently started working with next.js, TypeScript, and Sanity, and everything has been going smoothly so far. I have multiple schemas defined in my project and it works fine in development. The linting checks also do not show any errors. However, when I ...

Executing a series of asynchronous HTTP calls in Angular until a specific condition is satisfied

In Angular, I am making an HTTP call that returns a promise. Currently, I am refreshing the call using setTimeout at regular intervals. Are there any built-in functions or design patterns available to handle this task more efficiently? ...

Convert TypeScript model to JSON while excluding properties with null values

When working with an Angular 4 App and a typescript model, I have defined a Person class as follows: export class Person{ fname:string, lname?:string } The 'lname' property in the model is optional. To populate the model in a component, I u ...