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.

AWS Q Developer image

Your AI Code Assistant

Implement features, document your code, or refactor your projects.
Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

Top comments (0)

👋 Kindness is contagious

DEV shines when you're signed in, unlocking a customized experience with features like dark mode!

Okay