Can you explain the purpose of using @inject() in dependency injection with tsyringe?

I'm currently delving into Dependency Injection with tsyringe. This is a new concept for me altogether.

The code snippet below is functional and successfully instantiates the dependencies using container.resolve(Foo).

import "reflect-metadata";
import { injectable, container } from "tsyringe";

class Database {
  get() {
    return "got-stuff-from-database";
  }
}

@injectable()
class Foo {
  constructor(private database: Database) {}

  checkDb() {
    return this.database.get();
  }
}

const fooInstance = container.resolve(Foo);
console.log(fooInstance.checkDb());

//=> got-stuff-from-database

The following snippet (taken mostly from their readme) is puzzling to me. I am unable to make it work or comprehend why we need to use inject when we already have the injectable decorator in the previous example. It seems like everyone else understands it without any trouble.

interface Database {}

@injectable()
class Foo {
  constructor(@inject("Database") private database?: Database) {}

  checkDb() {
    return 'stuff';
  }
}

const fooInstance = container.resolve(Foo);
console.log(fooInstance.checkDb());

Answer №1

To better grasp the concept, it's important to remember that tsyringe is a library specifically designed for Typescript. When your Typescript code is compiled into Javascript, the interfaces essentially disappear (such as the Database interface in your example), making it impossible for the dependency injection process to proceed as usual. The documentation explains this dilemma:

Interfaces lack type information during runtime, hence requiring us to annotate them with @inject(...) so the container can resolve them correctly.

The reason why it's not functioning as expected for you is because you've only informed the DI framework to search for an object registered under the token "Database", which doesn't actually exist. To rectify this, you need to explicitly specify to tsyringe that the token "Database" corresponds to a specific class or instance like so:

container.register("Database", {
  useClass: SomeDatabaseImplementation
});

Keep in mind that you'll also have to create the mentioned implementation since interfaces cannot be instantiated directly. For a more comprehensive understanding, delving into the source code of the library would be beneficial as it offers a straightforward explanation and insight into its internal workings.

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 process response in React using Typescript and Axios?

What is the proper way to set the result of a function in a State variable? const [car, setCars] = useState<ICars[]>([]); useEffect(() =>{ const data = fetchCars(params.cartyp); //The return type of this function is: Promise<AxiosRespo ...

Using Angular 2, NodeJS, and Mongoose to send data from an Angular 2 frontend to a NodeJS backend REST API. However, encountering an issue where the Node API logs show that the OPTIONS

I am facing an issue with sending data from my Angular2 frontend API to the backend client, which is built using NodeJS and mongoose. When I inspect the data being sent on the Angular2 client through console.log, I can see that the correct values are being ...

Incorporating information into the output of an HTTP request with Angular 7

I have a list of asset IDs (assetIDs) and I need to fetch data using these IDs. Each HTTP request returns one or more datasets. My goal is to include the request ID in each dataset and then return the data. The process of fetching and returning the data i ...

Defined a data type using Typescript, however, the underlying Javascript code is operating with an incorrect data type

Recently delving into Typescript and following along with an educational video. Encountered a strange behavior that seems like a bug. For instance: const json = '{"x": 10, "y":10}'; const coordinates: { x: number; y: number } = JSON.parse(json); ...

What is the process for developing an interface adapter using TypeScript?

I need to update the client JSON with my own JSON data Client JSON: interface Cols { displayName: string; } { cols:[ { displayName: 'abc'; } ] } My JSON: interface Cols { label: string; } { cols:[ { label:&a ...

Sending input in a nested event listener

I am currently utilizing Highcharts for the purpose of showcasing an interactive map with custom countries. I have a specific requirement to enable the drilldown functionality, which involves clicking on a country to zoom in on another map displaying inter ...

Angular httpClient: Adjusting date format within json object

I need help converting the date property of an object to a format that the server can understand when using httpClient.post(...). Currently, the date property has its natural string representation. What steps can I take to make sure it is in the correct ...

What is the purpose of a Typescript function that returns a function with a generic type?

I recently stumbled upon a perplexing piece of TypeScript code that revolves around the function componentControl. Despite my efforts, I find myself struggling to fully comprehend its purpose and functionality. componentControl: const componentControl: &l ...

The CastError occurred because the attempt to add a string value to an array failed when converting it to a string

An issue I am encountering: *CastError: Cast to string failed for value "[ 'ZTM', 'NASA' ]" (type Array) at path "customers" at model.Query.exec (/Users/mike/Documents/NodeJS-applications/NASA-project/server/node_modules/mongoose/lib/qu ...

When working with Angular 2, it is important to note that the NgFor directive only supports binding to Iterables like Arrays. If you encounter an error message stating "Cannot find a differ supporting object '[object Object]' of type 'leaveType

After an extensive search and exploration for a solution to my problem, I found one, but unfortunately it didn't work as expected. The issue at hand involves displaying static data/list in dropdown options using TypeScript. Currently, I am working wit ...

Is there a possible solution to overcome the type error when utilizing dynamic environment variables in conjunction with TypeORM and TypeScripts?

I'm currently working on a backend project using the TsED framework, which leverages TypeScript and ExpressJS. To work with TypeORM, I have also integrated the dot-env package in order to utilize custom environment variables sourced from a .env file ...

Deep copying arrays in Typescript using the spread operator

I'm really struggling to grasp the concept of the spread operator in TypeScript. Every time I try to use it to duplicate object1. let object2 = { ...object1, }; I end up with a brand new object2 that contains all the items from object1, even if t ...

Angular Snake Game glitch - Snake fails to appear

As I embark on the initial phase of developing a snake game, the following steps are required: 1- Establish the game board 2- Create the snake and fruit elements 3- Display the snake and fruit accordingly However, I encounter an issue where the board gets ...

The parameter 'Barable' cannot be assigned to the parameter 'T' as they are not compatible

Could anyone help me understand why this code isn't functioning as intended: class Fooable { foo: string; } class Barable extends Fooable { bar: boolean; } function simplifiedExample<T extends Fooable>(): Array<T> { let list ...

Adjusting characteristics in Angular dynamically through JSON

Having trouble changing the value of [icon]="reactAtom" to use a JSON value? Need assistance in updating the [icon] value based on the 'featureItem' received from the parent component. HTML <div> <fa-icon [icon]="reactAtom" class="i ...

How important is it to maintain synchronization with $inject?

Currently diving into the Angular documentation regarding dependency injection, I'm pondering over the concept of staying 'in sync'. In essence, what distinguishes keeping things 'in sync' from maintaining them 'in the same o ...

Creating the data type for the input file's state: React with Typescript

Encountering an error when attempting to define the type of a file object within state: Argument of type 'null' is not assignable to parameter of type 'File | (()=> File)'.ts. Currently working on an upload component that allows for ...

What is the process for changing a field in a document on firestore?

Is there a way to modify a specific field in a firestore document without retrieving the entire document beforehand? ...

Conditional generic type in return type with Typescript

How can I condition the generic return type when a value is not present? type Foo = {}; class Bar<P extends Foo> { static make<P extends Foo>(a?: P): Bar<P> { return new Bar(); } } Bar.make() // returns Bar<Foo> ...

Error encountered in Typescript while attempting to $set a subdocument key value in MongoDB

This is a sample data entry. { _id: ObjectId('63e501cc2054071132171098'), name: 'Ricky', discriminator: 7706, registerTime: ISODate('2023-02-09T14:23:08.159Z'), friends: { '63e502f4e196ec7c04c4 ...