Tips for selectively expanding a class with methods and properties within Typescript object-oriented programming

My situation involves managing multiple forms with various fields such as checkboxes, uploads, and inputs. The challenge is that each form requires different classes for handling them - one form may need both inputForm and uploadForm, while another may only require checkboxForm. How can this be effectively handled in an object-oriented programming approach?

One approach I have considered is using a configure parameter, but this poses the issue of auto-completion displaying non-initialized fields which I would prefer to keep hidden from the client. While aware of the decorator pattern, implementing it seems like it could result in a convoluted solution with multiple wrappers.

class InputForm {
    // Define InputForm class here
}

class UploadForm {
    // Define UploadForm class here
}

class CheckboxForm {
    // Define CheckboxForm class here
}

interface Config {
    includeInputForm: boolean;
    includeUploadForm: boolean;
    includeCheckboxForm: boolean;
}

class MultiForm {
    inputForm?: InputForm;
    uploadForm?: UploadForm;
    checkboxForm?: CheckboxForm;


    constructor(private config: Config) {
        if (this.config.includeInputForm) {
            this.inputForm = new InputForm();
        }
        if (this.config.includeUploadForm) {
            this.uploadForm = new UploadForm();
        }
        if (this.config.includeCheckboxForm) {
            this.checkboxForm = new CheckboxForm();
        }
    }
}


const config: Config = {
    includeInputForm: true,
    includeUploadForm: false,
    includeCheckboxForm: true
};

const multiForm = new MultiForm(config);

Answer №1

When working with TypeScript, it's important to note that a class declaration must have members known statically. This means that instances of classes are essentially implemented as interfaces, and these interfaces require known members at compile time. Therefore, scenarios where different instances of a class have varying keys, like the example below, are not feasible:

class MultiForm {
  ⋮
}
const mf1 = new MultiForm(config1);
const mf2 = new MultiForm(config2);

In this case, both 'mf1' and 'mf2' cannot have different known keys. They either both need an 'inputForm' property or neither should have it.

So, in simple terms, the answer to the question posed is "no, this cannot be achieved."


However, there is a workaround where you can describe the type of a class constructor to mimic this behavior. By creating a type alias and using type assertions, you can achieve the desired outcome:

class _MultiForm {
  ⋮
}
type MultiForm<T extends Config> = ⋯;
const MultiForm = _MultiForm as 
  new <T extends Config>(config: T) => MultiForm<T>;
const mf1 = new MultiForm(config1);
const mf2 = new MultiForm(config2);

This approach involves utilizing generic types and type aliases to ensure that instances of 'mf1' and 'mf2' can have different keys based on the subtype of 'Config' provided.

While this solution may work in certain cases, it comes with its limitations and complexities. It's essential to thoroughly test the implementation, especially in scenarios where classes must have statically known keys, as illustrated in the following snippet:

class Oops<T extends Config> extends MultiForm<T> { } // error!
// --------------------------------> ~~~~~~~~~
// Base constructor return type 'MultiForm<T>' is not an 
// object type or intersection of object types with 
// statically known members.

Despite its effectiveness, adopting this method introduces complexity and pushes against the TypeScript type system. Consider if such convoluted solutions are necessary for your use case before proceeding with them.

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 element is inherently an 'any' type as the expression of type 'number' does not have the capability to index type 'Object'

Hey there, I'm currently in the process of learning Angular and following along with the Note Mates tutorial on YouTube. However, I've hit a stumbling block as I attempt to implement sorting by relevancy. The issue lies with the code snippet belo ...

What are the steps for importing a file into a React app that is built using Create React App as plain text?

Objectives I aim to showcase code snippets from the project itself for reference. I intend to keep the displayed code up-to-date with its implementation. I prefer not to remove myself from create-react-app This React project, built using create-react-ap ...

I'm wondering why the keys in my string object for a select box are being transformed into numbers after deploying my Next.js application

Within my next.js application, I have implemented an object with string keys and string values within a select box, as shown below: export const HOURS: { [key: string]: string } = { '00': '00', '01': '01', &ap ...

Is it possible to add additional text to an input field without modifying its existing value?

I have a numerical input field labeled "days" that I want to add the text " days" to without altering the actual numerical value displayed. <input type="number" class="days" (keyup)="valueChanged($event)"/> Users should only be able to edit the num ...

Encountering difficulty locating <arg" while providing argument to redux-saga using typescript

My takeLatest() saga function is calling postDeliverySubmitSaga(), and I need to pass arguments to it. This is how I'm defining my functions: export function* postDeliverySubmitSaga({ payload: any }: ReturnType<typeof setDeliverySubmit>) { ...

Verify if the keys are present within the object and also confirm if they contain a value

How can we verify keys and compare them to the data object? If one or more keys from the keys array do not exist in the object data, or if a key exists but its value is empty, null, or undefined, then return false; otherwise, return true. For example, if ...

Setting default property values in a React component using Typescript

   Is there a way to define default property values in React components when using Typescript? I came across a post on SE suggesting the use of a static class variable called defaultProps with key-value pairs for properties. However, this method didn&a ...

Maintaining type information while iterating over an object with Typescript

I am faced with the challenge of wrapping functions within an object in order to use their return values, all without altering their signature or losing type information. // An object containing various functions const functions = { foo, bar, baz } // Exa ...

Contrast the different characteristics of string dynamic arrays in Angular 6

I am working with two arrays of strings. One array is a dynamic list of checkboxes and the other is the source to check if the item exists in the first array. I need to implement this dynamically using Angular 6, can you help me with this? Currently, the ...

Error in Angular Standalone Component Routing: ActivatedRoute Provider Not Found

I'm currently developing an Angular application that incorporates standalone components. The goal is to set up routing for navigation to the home component. However, I encountered an error when trying to navigate using <a [routerLink]="[' ...

When I try to load JSON data using the http.get() method in my Angular 2 template, it returns

I've encountered an issue while attempting to read and parse a local json file into a custom class I created. The problem arises when trying to access properties of the class, as it throws errors indicating that the class is either null or undefined. ...

Troubleshooting React Typescript and Bootstrap - Issues with Collapse Component

I've encountered an issue in my React TypeScript app with Bootstrap 5. The app was set up using create-react-app and Bootstrap was added with npm i bootstrap. There is a button in the app that triggers the visibility of some content, following the ex ...

Tips for importing a file with a dynamic path in Angular 6

I'm facing an issue where I need to import a file from a path specified in a variable's value. For example, it looks like this: let test = require(configurationUrl); Here, configurationUrl represents a path such as '../../assets/app.conf.j ...

The process of declaring a nullable callback variable in TypeScript

Can the declaration of the resolve variable in the TypeScript code below be simplified while maintaining type safety? I am new to TypeScript, so please bear with me. The objective is to store the promise resolver callback that is passed to the executor fu ...

manipulator route in Nest.js

I have the following PATCH request: http://localhost:3000/tasks/566-344334-3321/status. The handler for this request is written as: @Patch('/:id/status') updateTaskStatus() { // implementation here return "got through"; } I am struggling t ...

Determine the accurate data type while iterating through a for loop

I am facing an issue where I have around 40 unique actions defined, all with the same parameters except for each being provided with a different schema which is causing the problem type ActionName = 'replaceText' | 'replaceImage'; type ...

`Why does the npm test command in vue2 source code fail with the error "Type ... is not assignable to type ..."?`

After cloning the Vue source code from github using git clone, I proceeded to install dependencies by running yarn. However, when I ran npm test, the test failed. https://i.sstatic.net/aZXBg.png Does anyone have insight on why this error occurred and how ...

Setting up event listeners from a string array (using PIXI.js)

Hey there! I've encountered a bit of an interesting challenge that could easily be resolved by duplicating the code, but where's the fun in that? This project is more of an experiment for me, just to prove that I can do it. However, the idea has ...

Drizzle ORM does not offer support for the Insert Returning feature

I am facing a query while utilizing Drizzle ORM with MySQL. At present, Drizzle ORM lacks an insert returning function for MySQL. Feel free to refer to this link for more information. My platform registers users into the system and generates JWT tokens u ...

The ts-loader, antd, and typescript trio hits a stumbling block with the module index.less nowhere to

I am incorporating the antd React component library in my project and I'm using ts-loader to efficiently load the components. Currently, I am facing an issue while trying to configure webpack to transpile less files. The error I am encountering is as ...