Tips for incorporating dynamic properties into TypeScript classes while ensuring accurate typing information

Within my coding project, I have a specific Users class that is being exported from the file named Users.ts

    export default class Users {}

This Users.ts file is then exported from another file called index.ts:

    // classes
    export {default as Users} from './Users'

In a third file labeled Foo.ts, my goal is to dynamically create instances of all the exported classes from index.ts and incorporate them as properties within that class:

    import * as classes from './index'

    class Foo {
        constructor() {
           const httpClient = new HttpClient()
        }

        _addClasses() {
           for (const classNames in classes) {
             this[classNames] = new classes[classNames](this.httpClient);
           }
        }
    }

My inquiry revolves around how to properly assign types to Foo, ensuring accurate autocompletion functionalities are available in the IDE when using .users like so:

new Foo(new HttpClient).users

Answer №1

In order to create a new type that includes the instance types of an imported module, we can utilize the predefined conditional type InstanceType to extract the instance type of a class. By using typeof classes, we can acquire the type of the module. Combining these within a mapped type results in:

type ClassInstances = {
    [P in keyof typeof classes]: InstanceType<typeof classes[P]>
}

// In this scenario, it equates to 
type ClassInstances = {
    Users: classes.Users;
}

The next step is to incorporate these new properties into the class without explicitly defining them. This can be achieved by utilizing an empty class expression as the base class for Foo and asserting that the instance returned by this empty class possesses those members (although it does not actually have them). By adding these members in _addClasses, the solution comes together seamlessly. The final code snippet looks like this:

import * as classes from './index';

type ClassInstances = {
    [P in keyof typeof classes]: InstanceType<typeof classes[P]>
}

class Foo extends (class {} as new () => ClassInstances) {
    httpClient: HttpClient;
    constructor() {
        super();
        this.httpClient = new HttpClient()
        this._addClasses();
    }

    _addClasses() {
        for (const cls of Object.keys(classes) as Array<keyof typeof classes>) {
            this[cls] = new classes[cls](this.httpClient);
        }
    }
}

new Foo().Users // Now with the name matching the export in index.ts, string manipulation on string properties is avoided.

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

How to stop a method in Angular2 when a specific response is received?

I've been grappling with the idea of unsubscribing from a method in Angular2 once it receives a specific response. settings.component.ts Within my component, the method in question is connectToBridge, where the value of this.selectedBridge is a stri ...

Typescript types cannot be combined together

Combining Types Is there a way to create a single type definition that incorporates the attributes of two separate types? type BlogPost = { title: string image: { src: string width: number height: number } content: ...

Retrieving a distinct value from an Observable

I am currently attempting to extract the monthlyFee value from this specific response body. ...

Angular 6: TypeError - The function you are trying to use is not recognized as a valid function, even though it should be

I'm currently facing a puzzling issue where I'm encountering the ERROR TypeError: "_this.device.addKeysToObj is not a function". Despite having implemented the function, I can't figure out why it's not functioning properly or callable. ...

What is the best way to restrict a mapped type in typescript to only allow string keys?

In the Typescript documentation, I learned about creating a mapped type to restrict keys to those of a specific type: type OptionsFlags<Type> = { [K in keyof Type]: boolean; }; If I want to use a generic type that only accepts strings as values: t ...

Changing the data type of a column in an Excel file from XLSX to

I am currently working with the XLSX npm package and attempting to download a sample Excel file, add some data to it, and then upload it back. The fields in the file include MOBILE NUMBER, DATE, TIME, and NAME. When I upload the file, the values for the DA ...

How can a nullable variable be converted into an interface in TypeScript?

Encountered an issue while working on a vue3.x typescript project. The vue file structure is as follows: <template> <Comp ref="compRef" /> </template> <script lang="ts" setup> import {ref} from "vue& ...

Angular - Array binding in view not refreshing

Within the following code snippet, the push function is utilized to transfer only the checked row from an array to another. Despite the successful execution of the push operation, the view does not reflect this update. onNextclick() { this.disable1 ...

Steps for generating a multer file using a link to an image

My current challenge involves downloading an image from a public URL, converting it into a multer file format, and then uploading it using an existing API. So far, I've experimented with axios using responseType: "blob" and responseType: "arraybuffer" ...

Struggling with a TypeORM issue while attempting to generate a migration via the Command Line

Having some trouble using the TypeORM CLI to generate a migration. I followed the instructions, but when I run yarn run typeorm migration:generate, an error pops up: $ typeorm-ts-node-commonjs migration:generate /usr/bin/env: ‘node --require ts-node/regi ...

Does the TS keyof typeof <Object> rule prohibit the assignment of object.keys(<Object>)?

I'm having trouble understanding the issue with this code snippet. Here is the piece of code in question: export type SportsTypes = keyof typeof SportsIcons export const sports: SportsTypes[] = Object.keys(SportsIcons); The problem arises when I at ...

Using aliases in npm packages is not supported

I am working on creating an npm package that I want to use in another application. During development, I set a path in tsconfig for importing various modules instead of using a relative path. However, when I download my package into the test app, it is una ...

Top location for securely storing information in Angular 8

I have developed a web application using Angular 8. My goal is to secure routes and pages with dynamic access levels. For instance, I want to verify if a user has access to a specific route, and if not, redirect them to the login page. To do this, I cur ...

The error message "Property 'data1' is not a valid property on the object type {}"

const Page: NextPage = ({data1}:{data1:any}) => { const [open, setOpen] = React.useState(false); const [data, setData] = React.useState(data1); const handleAddClick = () => { setOpen(true); }; ..... } export async function getServerS ...

A capability that operates on an array of pairs as its parameter, where the primary component of each pair signifies the superior category of the secondary

I'm grappling with developing a TypeScript function that takes an array of Tuples as input. Each tuple should consist of two elements, where the first element acts as a parent type to the second element - essentially, the second element must extend th ...

There seems to be an issue with a potentially null object in an Angular project while trying to view a PDF file

IDENTIFY THE ERROR: printContents = document.getElementById('print').innerHTML.toString(); ON LINE 4: print(): void { let printContents!: string; let popupWin!: any; printContents = document.getElementById('print').innerHTM ...

How can I verify if there are duplicate items in the cart using Angular 5?

As a newcomer to Angular 5, I am delving into creating a basic shopping cart to master the framework. However, I am currently facing a dilemma regarding how to handle duplicate entries in the cart data. Specifically, I am unsure whether I should store obje ...

How to programmatically close an Angular 5 Modal

In my current project, I am working with Angular 5. One of the functionalities I have implemented is a modal window. The HTML structure for this modal looks like this: <div class="add-popup modal fade" #noteModal id="noteModal" tabindex="-1" role="dia ...

The interface 'HTMLIonIconElement' is not able to extend both 'IonIcon' and 'HTMLStencilElement' types at the same time

After upgrading my Angular Ionic app to use Angular v13 from Angular 12 with the command ng update, I encountered errors preventing me from running the application successfully. [ng] Error: node_modules/ionicons/dist/types/components.d.ts:66:15 - error TS2 ...

The Typescript error message states that the type '{ onClick: () => void; }' cannot be assigned to the type 'IntrinsicAttributes'

I'm a beginner in Typescript and I'm encountering difficulties comprehending why my code isn't functioning properly. My goal is to create a carousel image gallery using React and Typescript. However, I'm facing issues when attempting t ...