Error: NestJS Decorator is throwing a Type Error and is not a function

Currently, I am in the process of developing an API using NestJS.

To enhance my API, I decided to integrate Redis and formulated a Dynamic Module that establishes a connection with Redis.
Furthermore, I incorporated Decorators for utilizing the redis connection.

However, I encountered an issue. Although I can access the Decorator in other services,
whenever I attempt to access it within the Module located in the same directory as the Decorator, I encounter a TypeError.

@InjectRedisGraph(MainGraph) private readonly graph: Graph,
                     ^
TypeError: (0 , redis_graph_connection_decorator_1.InjectRedisGraph) is not a function

Here are the solutions I have attempted so far:

  • I tried setting both absolute and relative paths for import, but neither succeeded
  • Exported a generic console.log function, which functions properly and gets executed
  • Added @Injectable decorator to the Module, however, it did not resolve the problem (Although the Injectable decorator itself did not trigger a TypeError)
  • Moving the declaration into the Module file does work, nevertheless, I prefer to keep the files separate

Upon examining the transpiled JS code, the exports of the decorator appear to be correct.
VS Code has no issues resolving all classes/functions.
When transpiling, tsc does not report any errors.
All configurations align with the default NestJS config settings.

Hopefully, this oversight is on my end. As a newcomer to NestJS and Typescript Decorators, I currently find myself a bit lost.

The Code: decorator

import { Inject } from '@nestjs/common'
import { RedisClientIdentifier } from './redis-graph-connection.provider'

/**
 * Simple decorator to make usage of graphredis more verbose
 */
export const InjectRedisGraph = (graph: symbol): ParameterDecorator => {
  return Inject(graph)
}

export function doesExport() {
  console.log("It does")
}

module

import { DynamicModule, Logger, OnApplicationShutdown } from '@nestjs/common'
import { createRedisGraphProviders } from './redis-graph-connection.provider'
import { RedisClientOptions } from '@redis/client'
import { doesExport, InjectRedisGraph } from './redis-graph-connection.decorator'
import { MainGraph } from '../redis-store.constants'
import { Graph } from '@redis/graph'

export class RedisGraphModule implements OnApplicationShutdown {
  static logger = new Logger('redis-graph-client')

  static async forRootAsync(
    options: RedisGraphModuleOptions,
  ): Promise<DynamicModule> {
    const providers = await createRedisGraphProviders(options)
    return {
      module: RedisGraphModule,
      providers,
      exports: providers,
    }
  }

  //            |-> This throws TypeError, not a function
  constructor(@InjectRedisGraph(MainGraph) private readonly graph: Graph) {
    doesExport()
  }

  onApplicationShutdown() {
    // do some graph cleanup
  }
}

some other service, This works

import { Injectable, Logger } from '@nestjs/common'
import { EvidenceStore } from 'src/common/evidence-store.interface'
import { InjectRedisGraph } from 'src/redis-store/redis-graph-connection/redis-graph-connection.decorator'
import { MainGraph } from './redis-store.constants'
import { Graph } from '@redis/graph'

@Injectable()
export class RedisStore implements EvidenceStore {
  private readonly logger = new Logger('redis-graph-collector')

  constructor(
    @InjectRedisGraph(MainGraph) private readonly redisGraph: Graph,
  ) {}
...

redis-graph-connection.provider

import { createClient, Graph } from 'redis'
import { Provider } from '@nestjs/common'
import { RedisGraphModule, RedisGraphModuleOptions } from './redis-graph-connection.module'

export const RedisClientIdentifier = Symbol('redisClient')

export async function createRedisGraphProviders(
  options: RedisGraphModuleOptions,
): Promise<Array<Provider>> {
  const client = createClient(options.redisOptions)
  client.on('error', (err: Error) => {
    RedisGraphModule.logger.error(err.message, err.stack)
  })

  await client.connect()
  RedisGraphModule.logger.log('Connected')

  const providers: Array<Provider> = [
    {
      provide: RedisClientIdentifier,
      useValue: client,
    },
  ]

  options.graphs.forEach((graphName) => {
    providers.push({
      provide: graphName,
      useValue: new Graph(client, graphName.toString()),
    })
    RedisGraphModule.logger.log(`Created graph for ${graphName.toString()}`)
  })

  return providers
}

Answer №1

The primary concern in this scenario is the presence of a circular file import within the decorator file and the module file. This issue results in one of the two files exporting undefined at runtime, only to later populate it once all dependencies have been resolved. When the decorator is called during file import, the dependency is still undefined, leading to the error being displayed. Circular imports are inherently unpredictable, which explains why this behavior can be inconsistent.

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

Using selectors and mappers in Typescript generics

I am looking to create a versatile selector and mapper method. interface State { user: { name: string; age: number; } } const pickName = (state: State) => state.user.name; const selectAge = (state: State) => state.user.age; ...

Tips for setting the state of a parent component in React JS when multiple children components are involved without causing conflicts

I have 3 child components that are updating a common parent state object. Each child component should only update its own field in the object. How can I achieve this? My objective is to keep track of the individual state of each child component. const Ch ...

The array does not yield any values when utilizing Angular CLI

Recently, I created a component that contains an array of strings. Here's the code snippet for reference: import {Component} from '@angular/core'; @Component({ selector: 'app-products-list', templateUrl: './products-list. ...

Tips on Including Service in Angular Testing Specification File with Jasmin/Karma

I'm a beginner when it comes to writing unit tests for Angular. I have a scenario where I need to inject a service into my controller file (.ts). How can I go about injecting the service file in the spec file? Below is the code snippet: app.componen ...

Experiencing a problem with updating records in angular?

angular version: Angular CLI: 9.0.0-rc.7 I have encountered an issue while trying to update a record. After clicking on the edit icon, I am able to make changes to the record in the form. However, when I click on the Edit Button, the record gets updated i ...

Angular 4: Decoding the json_callback response from the server

When using Angular 4, I made a GET request to the following URL: Here is the code I used: this.http.get('https://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=JSON_CALLBACK', { params: { format: 'json', tagmode: & ...

Angular 2: Enhancing Tables

I am looking to create a custom table using Angular 2. Here is the desired layout of the table: https://i.sstatic.net/6Mrtf.png I have a Component that provides me with data export class ResultsComponent implements OnInit { public items: any; ngO ...

Is there a way to remove the sign up link from the AWS Amplify Vue authenticator?

Utilizing the amplify-authenticator component from the aws-amplify-vue library to manage authentication in my application. I am currently exploring methods to disable the "Create Account" link on the front end interface, but haven't found a direct sol ...

By default, showcase the value of the first item in the list selected in a mat-selection-list on a separate component

In my project, I have two essential components: 1)list (which displays a list of customers) 2)detail (which shows the details of a selected customer) These components are designed to be reusable and are being utilized within another component called cus ...

Level operations for tuple labels

Is it possible in TypeScript 4 to achieve something similar to the code snippet below using labelled tuples? type stringProperties<T extends {}> = {[k in keyof T]: string} This concept would allow me to transform a type like [foo: boolean, bar: numb ...

Is there a way to stop Vuex from causing issues with my class instance?

I am attempting to save a representation of a class in Vuex, specifically the EditorState from ProseMirror. The class's properties are mostly unchangeable externally, meaning that any modifications require replacing the existing instance with a new on ...

Issue with rejecting a promise within a callback function in Ionic 3

Within my Ionic 3 app, I developed a function to retrieve a user's location based on their latitude and longitude coordinates. This function also verifies if the user has location settings enabled. If not, it prompts the user to switch on their locati ...

Placing options and a clickable element within a collapsible navigation bar

Within my angular project, there are 4 input fields where users need to enter information, along with a button labeled Set All which will populate them. https://i.sstatic.net/1GGh1.png I am wondering how I can organize these input fields and the button i ...

Refreshing a component within the ngrx/store

Currently utilizing @ngrx/store within my Angular 2 application. The store contains a collection of Book objects. I aim to modify a specific field within one of those objects. Additionally, there is an Observable representing the Book instance I wish to u ...

Efficiently implementing state and dispatch for useReducer in TypeScript with React

I'm encountering an error in my current setup. The error message reads: 'Type '({ team: string | null; } | { team: string | null; } | { ...; } | { ...; } | { ...; } | Dispatch<...>)[]' is missing the following properties from t ...

Newcomer to Typescript struggles with implementing system.js module loader with typescript

Currently, I am delving into the realm of Typescript and endeavoring to incorporate module loaders (system.js) into my workflow. However, I have encountered an error that seems quite elusive to resolve. Undoubtedly, there must be a misconfiguration on my p ...

Error alert! A token error has been detected while executing Angular tests under <Jasmine>

I've been navigating the world of Angular testing, but I've hit a roadblock that I can't seem to bypass. Despite my efforts to consult the documentation and scour Google for answers, I remain stuck with a cryptic error message stating "Inval ...

Setting default values for multiple selections can be accomplished by following these steps

I am working on a form that collects information about streets and their corresponding neighborhoods: https://i.sstatic.net/FAZLK.png When I click on a button in the grid to edit, the street data is displayed like this: https://i.sstatic.net/UHiLX.png ...

Mastering the art of implementing md-table with services in Angular 4

I am a newcomer to the world of angular and I am attempting to utilize the new md-table component in Angular Material 2 with Angular 4. I have created a service that fetches simple arrays of content from an API. However, I am struggling to use this servic ...

Using TypeScript, the Generator functions in Redux Saga do not execute nested effects in sequence when using yield put

I need to handle multiple asynchronous actions and ensure that a third action is only triggered after the first two have successfully completed. I have created three saga workers for this purpose: export function* emailUpdateRequestSaga(action: IEmailUpda ...