Utilizing a static attribute in conjunction with generic types: How to do it effectively?

I am working on a piece of code where I have a constructor and call a static method to set a static variable.

export abstract class AbstractRepository<T extends Typegoose> {
  private static conn: SessionDb<T>; // <-- Encountering a compile error here!
  protected model: Model<InstanceType<T>, {}>;

  constructor(entity: T, collectionName: string){
    if(AbstractRepository.conn == null) AbstractRepository.conn = SessionDb.connect(entity);
    this.model = AbstractRepository.conn.getModel(collectionName);
  }  
}

I need help with typing the conn: SessionDb <T> attribute.
This particular variable is connected to a mongoose connection.
Is it advisable to store a singleton variable for future accesses?

Answer №1

Issue

Dealing with generic classes can be tricky, especially when defining the generic parameter T for each instance. While specifying the type T during the creation of a generic class instance is possible, it is often unnecessary due to the constructor signature providing TypeScript with the necessary information about the relationship between the arguments and the generic type T.

By utilizing constructors like

constructor(entity: T, collectionName: string)
, TypeScript effectively assigns the type of the variable entity as the generic type T for that specific instance. Consequently, creating instances such as
const myObj = new ConcreteRepository(myEntity, myCollectionName);
allows TypeScript to determine the type of myObj as
ConcreteRepository<typeof myEntity>
.

However, when it comes to static properties, they belong to the class itself and are shared among all instances rather than being dependent on the current instance's generic type T. This can lead to confusion and inefficiencies in managing static variables tied to generic types.

Resolution 1

To address this concern, transforming the static variable conn into an instance variable within each instance of a class ensures that conn corresponds to the entity type associated with that instance. Each instance sets its own connection using this.conn in the constructor.

export abstract class AbstractRepository<T extends Typegoose> {
  protected conn: SessionDb<T>;
  protected model: Model<InstanceType<T>, {}>;

  constructor(entity: T, collectionName: string){
    this.conn = SessionDb.connect(entity);
    this.model = this.conn.getModel(collectionName);
  }
}

This design enables implementing the base class by either generic classes or those bound to a specific value of T.

Resolution 2

An alternative solution involves making use of an abstract class like AbstractRepository, which cannot be directly instantiated but must be extended by other classes. For instances where extending classes cater to specific entity types, each class can have its unique static conn variable.

The implementation might resemble the following structure:

export abstract class AbstractRepository<T extends Typegoose> {
  protected model: Model<InstanceType<T>, {}>;

  constructor(entity: T, collectionName: string){
    this.model = this.getConnection().getModel(collectionName);
  }

  abstract getConnection(): SessionDb<T>;
}

export class SpecificRepository extends AbstractRepository<SpecificType> {
    private static conn: SessionDb<SpecificType>;

    getConnection(): SessionDb<SpecificType> {
        if( SpecificRepository.conn === undefined) {
            // additional logic required based on entity information
            SpecificRepository.conn = SessionDb.connect(entity);
        }
        return SpecificRepository.conn;
    }
}

In this case, the base class mandates that each subclass implements a method getConnection returning a matching SessionDb for type T. Although the actual implementation is left to the subclasses, the base class can safely utilize this method when needed.

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

Tips for sorting grouped items in MongoDB?

The official mongo documentation includes an example in the aggregate section that showcases the usage of $graphLookup with a reportingHierarchy field in each result element. However, how can you filter the final elements set within specific keys? { "_id" ...

Creating filters with Angular ES5 is a powerful tool for manipulating data in

Struggling with creating a pipe filter in Angular v 4.4.4 using ES5 for table results populated by *ngFor. Despite extensive research, no examples can be found. Is this even possible? If so, could someone please provide an example? This is the code snippe ...

Designing architecture for NPM packages in TypeScript

I am currently developing multiple NPM packages using TypeScript and I am exploring the most effective strategies for supporting various target architectures. When compiling to ES3, there is extensive support but it comes with additional boilerplate for c ...

Guide to accessing specific fields from a JSON object array using Angular's HTTP service and returning them as a response

My Interface definition: export interface User { id: number; name: string; } The API response I received: [ { "id": 1, "name": "Leanne Graham", "username": "Bret", ...

What should I do when dealing with multiple submit buttons in NextJS?

How can I differentiate between two submit buttons in a form component created in Next.js? I'm struggling to determine which button was pressed and need help resolving this issue. import React from "react"; const LoginPage = () => { as ...

What is the best way to set up initial state in react-native-day-picker?

I have been experimenting with implementing react-native-calendar into my project. Here is the code snippet I am working on: import React from 'react'; import {Calendar} from 'react-native-day-picker'; const MyCalendar = () => { ...

I am looking to fetch an array of objects using Mongoose. However, I am only interested in extracting two specific

Currently, I am exploring Mongoose with JavaScript. This is the mongoose schema I am working with: const product = new mongoose.Schema({ name: { type: String, required: true, unique: true }, quantity: { type: Number, required: ...

retrieve the most recent 30 entries from the mongoDB database

Can you retrieve the most recent 30 records or any specified number of records that were inserted into a mongoDB database using the find method excluding all parameters? db.tweets.find({}, function(err, docs){ response.end(JSON.stringify(docs)); }); ...

What method can be used to automatically set the headerTooltip in ag-grid to match the data displayed in the cell?

Looking for some assistance with ag-grid. I'm trying to implement a default tooltip on every grid in my application. The tooltip value should display the same value as the cell someone is hovering over. I attempted to achieve this using the following ...

What benefits can be gained from combining Protractor with a Selenium framework such as Serenity?

Do we need to have both Protractor tests and Serenity tests for an Angular8 project? (Serenity is a Selenium framework for test automation) It appears that they perform the same functions and serve the same purpose, so would it be redundant to have both s ...

Troubleshooting Node.js - MongoDB document removal issue

I am attempting to delete all documents from a collection that contain a field named uuid with values matching the $in operator along with an array I provide. However, for some reason the deletion is not functioning as expected. Below is the code snippet a ...

Contrasting a basic array of Validator functions with the application of Validators.compose on the array

I'm curious about the specific distinction between a straightforward array of validator functions like the example below (extracted from the official angular 2 documentation): buildForm(): void { this.heroForm = this.fb.group({ 'name ...

What is causing the warnings for a functional TypeScript multidimensional array?

I have an array of individuals stored in a nested associative array structure. Each individual is assigned to a specific location, and each location is associated with a particular timezone. Here is how I have defined my variables: interface AssociativeArr ...

What is the best way to compare two date strings with the format dd/mm/yyyy using JavaScript?

When attempting to compare a "Date" type of data with an "Any" type of data, the comparison is not functioning as expected. The date is retrieved in the following code: var today = new Date(); var dd = String(today.getDate()).padStart(2, '0'); v ...

Using the concat operator along with the if statement in Angular to make sequential requests based on certain conditions

Managing multiple HTTP requests in a specific order is crucial for my event. To achieve this, I am utilizing the concat operator from rxjs. For instance, upon receiving data from the first request, I update local variables accordingly and proceed to the ne ...

Is it possible to create a reusable TypeScript interface for an array of functions?

Currently working with Vue and Typescript, I'm exploring different ways to describe types for an array of functions. In my current code, I have the following setup. Is there a way I could define an interface called formRules instead of repeatedly decl ...

Deleting multiple records from an array in MongoDB

Within my document, there exists an array structured as follows: { "differentialDiagnosis" : "IART/Flutter", "explanation" : "The rhythm.", "fileName" : "A115a JPEG.jpg", "history" : "1 year old with fussiness", "interpreta ...

Typescript failing to indicate that an object may be null or undefined

I can't seem to get TypeScript to recognize that types with | null are nullable. Take a look at the example below where I define the type: type A = { b: { c: number; d: string; } | null; }; When I hover over b, it doesn't ...

What is the best way to import styles for desktop or mobile devices?

I manage three main folders on my project: base, pc, and mobile. The index.scss file from the base folder is always connected through the css section in nuxt.config.js. To distinguish between different device types, I utilize the @nuxtjs/device module. N ...

Executing an HTTP POST request without properly encoding a specific parameter

I am attempting to communicate with an unauthorized third-party API using Node and the request module. Below is the code that generates the request: request.post( { url: url, headers: MY_HEADERS_HERE, followAllR ...