What could be causing the class methods in my NestJS DI to be stored as undefined values in a map?

I came up with an EventService to manage custom events that are added through a special decorator. Everything appears to be functioning correctly, but the issue arises when attempting to access the methods within the stored event class as they return undefined.

The puzzling part is that the class itself seems to be initialized.

What could be causing this particular behavior?

event.service.ts

@Injectable()
/**
 * @class EventService
 */
export class EventService {
    /**
     * @private
     * @readonly
     * @type {Logger}
     */
    private readonly logger: Logger = new Logger(EventService.name);

    /**
     * Event Storage
     *
     * @private
     * @readonly
     * @type {Map<string, BaseEvent>}
     */
    private readonly _events: Map<string, BaseEvent> = new Map<
        string,
        BaseEvent
    >();

    /**
     * Add Event
     *
     * @public
     * @async
     * @param {string} key Event Name
     * @param {BaseEvent} event Event Class
     * @param {boolean} overwrite Overwrite Event in Map
     * @returns {Promise<void>}
     */
    public async add(
        key: string,
        event: BaseEvent,
        overwrite = false
    ): Promise<void> {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const className = (event as any).name;
        const hasRegistered = await this.has(key);

        if (hasRegistered && !overwrite) {
            this.logger.error(`${key} already registered with: ${className}`);
            return;
        }

        if (hasRegistered && overwrite) {
            this._events.set(key, event);
            this.logger.log(
                `${key} got overwritten by event class: ${className}`
            );
            return;
        }

        this._events.set(key, event);

        console.log(event);
        console.log(event.test);

        this.logger.log(`${key} was registered to: ${className}`);
    }
}

event.decorator.ts

/**
 * Bind Event to Class
 *
 * @function
 * @param {string} name Event Name
 * @param {boolean} client Determinate if its a client event
 * @param {string} overwrite Overwrite existing event
 */
export function Event(name: string, client = false, overwrite = false): any {
    return (constructor: any) => {
        return class extends constructor {
            constructor(...args: any[]) {
                super(args);

                const eventService: EventService = this.eventService[0];
                eventService.add(name, constructor, overwrite);
            }
        };
    };
}

player-join.event.ts

@Injectable()
@Event('playerJoin')
export class PlayerJoinEvent extends BaseEvent {
    /**
     * @private
     * @readonly
     * @type {Logger}
     */
    public readonly logger: Logger = new Logger(PlayerJoinEvent.name);

    /**
     * Handle Player Join
     *
     * @public
     * @async
     * @param {any} player Joining Player
     * @returns {Promise<void>}
     */
    public async execute(player: string): Promise<void> {
        this.logger.log(`${player} joined the server`);
    }

    public test(): void {
        this.logger.debug('hi');
    }
}

Console Output

[Nest] 22508  - 20.09.2022, 19:44:48     LOG [NestFactory] Starting Nest application...
[Nest] 22508  - 20.09.2022, 19:44:48     LOG [InstanceLoader] AppModule dependencies initialized +24ms
[class PlayerJoinEvent extends BaseEvent] // these both logs are in the EventService.ts after adding them
undefined
[Nest] 22508  - 20.09.2022, 19:44:48     LOG [EventService] playerJoin was registered to: PlayerJoinEvent

Answer №1

event represents the class reference. Calling event.test will search for the static method on the event class, not the instance method. To access the instance method test, you can do so by referencing it through the prototype (e.g. event.prototype.test), or by passing the instance of the BaseEvent instead of just the reference to it.

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

Utilizing v-for in Vue with TypeScript to generate multiple checkboxes

My goal was to capture the values of checkboxes and store them in an array using v-model. However, I encountered an issue where the first time I toggle a checkbox, it doesn't register. Only after checking a second box and hitting submit does the secon ...

Exploring the functionality of window.matchmedia in React while incorporating Typescript

Recently, I have been working on implementing a dark mode toggle switch in React Typescript. In the past, I successfully built one using plain JavaScript along with useState and window.matchmedia('(prefers-color-scheme dark)').matches. However, w ...

Unsubscribing from a nested observable - a step-by-step

In our Angular component, we leverage the ngOnDestroy() method to handle canceling http requests that are still pending when navigating away from a page. To avoid reloading data that has already been fetched, we utilize a custom generic cache helper on cer ...

Showing a header 2 element just once using both *ngFor and *ngIf in Angular

I have an array of words with varying lengths. I am using ng-For to loop through the array and ng-if to display the words based on their lengths, but I am struggling to add titles to separate them. Expected Outcome: 2 letter words: to, am, as... 3 lette ...

Using Angular 4's ngModel can result in the transformation of data type from 'number' to 'string'

I am facing an issue with my Angular4 app where data captured from a form is stored in DynamoDB. The problem arises when an input field typed as 'text' is bound to a Typescript 'number' field, which seems to be converting the object val ...

Exploring the process of associating a string with a specific enum value in TypeScript

One scenario is if you receive a string value from the server and have an enum type with string values defined. In TypeScript, how can you convert the string value to the enum type? export enum ToolType { ORA= 'orange', ST= 'stone' , ...

Enhance the aesthetic appeal of the imported React component with added style

I need assistance with applying different styles to an imported 'notification' component within my header component. The notification component has its own CSS style, but I want to display it in the header component with unique styling. How can I ...

Retrieve the response type from a Prisma FindUnique query

Essentially, my goal is to determine the type of the result obtained from a FindUnique operation in Prisma. The current return type is any: import prisma from "@/libs/prismaDb"; import { Prisma } from "@prisma/client"; export default a ...

Is it necessary to use Generics in order for a TypeScript `extends` conditional type statement to function properly?

Looking to improve my understanding of the extends keyword in TypeScript and its various uses. I recently discovered two built-in utilities, Extract and Exclude, which utilize both extends and Conditional Typing. /** * Exclude from T those types that are ...

Unable to start an expo project in bare workflow using TypeScript

Can someone help me with setting up an expo bare workflow using TypeScript? I ran the command "expo init [project name]" in my terminal, but I can't seem to find the minimal (TypeScript) option. ? Choose a template: » - Use arrow-keys. Return to sub ...

Uncover the value type of a key in TypeScript without using a discriminated union

I want to implement a type map that ensures the type of an object's value for a specific key is determined by the value of another key. For example: type CurrencyValue = { code: string; value: number; }; type FieldMap = { text: string; curren ...

Check the functionality of a React functional component by conducting unit tests on its functions

Is there a way to properly unit test a function within a Functional component in React? Since wrapper.instance() will return null for functional components, what is the best approach to ensure this function is included in testing to achieve maximum coverag ...

What is the step-by-step process for implementing tooltips in Ant Design Menu after version 4.20.0?

According to the Ant Design documentation: Starting from version 4.20.0, a simpler usage <Menu items={[...]} /> is provided with enhanced performance and the ability to write cleaner code in your applications. The old usage will be deprecated in th ...

When using a try-catch block to validate an object, why does the Liskov Substitution Principle (LSP) fail to correctly

function parseAndValidate(obj: unknown): ParsedObj | void { try { // conducting various validations return parsedObj } catch { throw new Error('obj is invalid') } } const parsedObj = parseAndValidate(obj) I ...

Attempting to utilize Pinia without a corresponding component will result in an error indicating that there are no

In my Vue.js 3 project using the ViteSse template, I encountered an issue when trying to access my Pinia store named notificationStore outside of the setup component. When running the dev command, I received an error message saying "getActivePinia called w ...

Fixing ngModel and click functionality issues in dynamic HTML content within Angular 4

I am struggling to insert HTML content into a specific id by using Angular. Although the HTML displays, the functionality of ngModel and click event is not working. How do I resolve this issue? app.component.html <div id="myid"> </div> app. ...

When using the async pipe with Angular's ngFor, an error message indicates that the argument is

Can you explain why this error message is appearing: Argument of type '[string, { startTime: string; endTime: string; }][] | null' is not assignable to parameter of type 'Collection<unknown>'. It occurs when attempting to utilize ...

Downloading fonts from Google Fonts is always a struggle when using Next.js

After initializing a fresh Next.js project using create-next-app, I managed to successfully launch it with npm run dev. However, an issue arises every time Next.js boots up, displaying the following error: FetchError: request to https://fonts.gstatic.com/ ...

Utilizing a variable name as an object key in TypeScript

Can this be achieved? static readonly statusMapping: { [key in UploadStatus]: PopupMessageStatus } = { UploadStatus.COMPLETED : PopupMessageStatus.COMPLETED } UploadStatus is an enum with numeric values, where UploadStatus.COMPLETED = 0 p ...

Implementing TypeScript type declarations for merging core types

Is there a way to perform type declaration merging in TypeScript for built-in types when using imports? I am currently attempting to merge interfaces as per the guidelines outlined in this documentation: https://www.typescriptlang.org/docs/handbook/declar ...