DEV Community

오병진
오병진

Posted on • Originally published at sunrabbit.durumis.com

6 5 4 4 4

Framework-Level DI Even for student Node.js Developers

When developing servers with Node.js, one often encounters the alluring temptation of Spring.

This is because of its structured, systematic nature, and the difficulty in breaking free from its constraints.

Therefore, in the Node.js community, a framework called Nest.js emerged.

It stemmed from the strong desire to develop servers in a structured format, similar to Spring.

However, Spring's DI utilizes runtime reflection at the language level to support DI.

Similarly, Dotnet uses attributes to track and perform DI through reflection.

So, how does Nest.js achieve DI?

Spring and Dotnet leverage reflection at the language level because their underlying languages are compiled languages.

But ECMAScript is merely an interpreted language, a commoner, isn't it?

Below is one example from the Nest.js tutorial.

import { Controller, Get, Post, Body } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';

@Controller('cats')
export class CatsController {
    constructor(private catsService: CatsService) {}
    @Post()
    async create(@Body() createCatDto: CreateCatDto) {
        this.catsService.create(createCatDto);
    }
    @Get()
    async findAll(): Promise<Cat[]> {
        return this.catsService.findAll();
    }
}
Enter fullscreen mode Exit fullscreen mode

Clearly, this TypeScript code, after compilation, will lack type tags. Therefore, it won't know the argument types needed for the constructor of the class.

The solution lay in the language specification.

Reflect

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect

Fortunately, there was a built-in feature that allows adding metadata to each object at the language level.

Image description

It's a simple function that adds and retrieves metadata from objects.

So, TypeScript thought:

What if we add type information to the metadata when compiling classes?

Therefore, TypeScript stores the information about the argument types needed for the constructor of a class in Reflect whenever a class decorator is used.

Image description

This doesn't involve any transformations or black magic; it's purely a feature of the TypeScript compiler.

With the types of the constructor's arguments stored in the class's metadata,

we can retrieve the types and use them accordingly.

You can examine the implementation in NestJS, but it's quite extensive, so I recommend another library.

https://github.com/microsoft/tsyringe/blob/master/src/decorators/injectable.ts

This library, created by Microsoft, has very clean code.

I recommend checking it out. This concludes the post.

Top comments (0)

Image of Timescale

📊 Benchmarking Databases for Real-Time Analytics Applications

Benchmarking Timescale, Clickhouse, Postgres, MySQL, MongoDB, and DuckDB for real-time analytics. Introducing RTABench 🚀

Read full post →

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay