068 Π Π°Π·Π±ΠΎΡ€ DI ΠΈ IOC

DI - dependency injection IOC - inversion of control

Π‘Π°ΠΌΠΎ явлСниС внСдрСния зависимостСй избавляСт нас ΠΎΡ‚ потрСбности инстанциирования ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π²Π½ΡƒΡ‚Ρ€ΠΈ самого класса. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π²Π½Π΅Π΄Ρ€ΡΡ‚ΡŒ Ρ€Π°Π·Π½Ρ‹ΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π» ΠΏΠΎ Π·Π°Ρ€Π°Π½Π΅Π΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠΌΡƒ интСрфСйсу.

Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ Ρ‚Π°ΠΊ ΠΆΠ΅ позволяСт ΠΎΡ‚Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½Ρ‹ΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π΅Π³ΠΎ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ ΠΏΡ€ΠΎΡ‚Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ

Π‘ΠΎΠ²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ самоС простоС Π²Π½Π΅Π΄Ρ€Π΅Π½ΠΈΠ΅ зависимостСй ΠΌΠΎΠΆΠ½ΠΎ:

  1. Π§Π΅Ρ€Π΅Π· конструктор
  2. Π›ΠΈΠ±ΠΎ Ρ‡Π΅Ρ€Π΅Π· ΠΌΠ΅Ρ‚ΠΎΠ΄

Composition root - это ΠΎΠ΄Π½Π° Ρ‚ΠΎΡ‡ΠΊΠ°, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΡΠΎΠ±ΠΈΡ€Π°ΡŽΡ‚ΡΡ всС зависимости с прилоТСния

Π­Ρ‚ΠΎ схСма простого DI, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΠΈΡ‚ΡŒ Π² любом языкС

А это схСма с Ρ‚ΠΈΠΏΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΌΠΈ языками, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΉ интСрфСйс Ρ‚ΠΎΠΉ зависимости, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π²Π½Π΅Π΄Ρ€ΡΡ‚ΡŒ Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡ выступаСт Π² Π΄Π°Π½Π½ΠΎΠΌ случаС Π½Π΅ΠΊΠΈΠΌ ΠΊΠΎΠ½Ρ‚Ρ€Π°ΠΊΡ‚ΠΎΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ опрСдСляСт Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΠΏΡ€ΠΈΡΡƒΡ‚ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Π² классС

И Π²ΠΎΡ‚ Ρ‚ΡƒΡ‚ ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Ρ‡Ρ‚ΠΎ наш интСрфСйс прСдставляСт ΠΈΠ· сСбя ΠΊΠΎΠ½Ρ‚Ρ€Π°ΠΊΡ‚ Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΠΏΡ€ΠΈΡΡƒΡ‚ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Π² классС

logger.interface.ts

import { Logger } from "tslog";
 
export interface ILogger {
	logger: unknown;
 
	log: (...args: unknown[]) => void;
	error: (...args: unknown[]) => void;
	warn: (...args: unknown[]) => void;
}

А Ρ‚ΡƒΡ‚ ΠΌΡ‹ ΠΏΠΎ ΠΊΠΎΠ½Ρ‚Ρ€Π°ΠΊΡ‚Ρƒ Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€ΠΈΡΡƒΡ‚ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Π² классС ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ

logger.service.ts

import { Logger } from "tslog";
import { ILogger } from "./logger.interface";
 
export class LoggerService implements ILogger {
	public logger: Logger<string>;
 
	constructor() {
		this.logger = new Logger();
	}
 
	log(...args: unknown[]) {
		this.logger.info(...args);
	}
 
	error(...args: unknown[]) {
		this.logger.error(...args);
	}
 
	warn(...args: unknown[]) {
		this.logger.warn(...args);
	}
}

И Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ Π² Π³Π»Π°Π²Π½ΠΎΠΌ классС ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ Π²Ρ…ΠΎΠ΄Π½ΠΎΠΉ инстанс Π½Π΅ Π½Π° сам класс Π»ΠΎΠ³Π³Π΅Ρ€Π°, Π° Π½Π° интСрфСйс, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌΡƒ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡƒΠ΄ΠΎΠ²Π»Π΅Ρ‚Π²ΠΎΡ€ΡΡ‚ΡŒ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Π΅ΠΌΡ‹ΠΉ Π²Π½ΡƒΡ‚Ρ€ΡŒ app Π»ΠΎΠ³Π³Π΅Ρ€

app.ts

export class App {
	private app: Express;
	private server: Server;
	private port: number;
	// ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π² сСбя Π»ΠΎΠ³Π³Π΅Ρ€ ΠΏΠΎ интСрфСйсу
	private logger: ILogger;
	private userController: UserController;
	private exceptionFilter: ExceptionFilter;
 
	constructor(
		// ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π² сСбя Π»ΠΎΠ³Π³Π΅Ρ€ ΠΏΠΎ интСрфСйсу
		logger: ILogger,
		userController: UserController,
		exceptionFilter: ExceptionFilter
	) {
		this.app = express();
		this.port = 8000;
		this.logger = logger;
		this.userController = userController;
		this.exceptionFilter = exceptionFilter;
	}
 
	// ΠΊΠΎΠ΄...
}

ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ ΠΎ Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ всС наши ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ максимально ΠΈΠ·ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ Π΄Ρ€ΡƒΠ³ ΠΎΡ‚ Π΄Ρ€ΡƒΠ³Π°. БвязываСм всС ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ Ρ‡Π΅Ρ€Π΅Π· абстракции ΠΈ интСрфСйсы, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‚ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ½Ρ‚Ρ€Π°ΠΊΡ‚ Π½Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ, которая Π΄ΠΎΠ»ΠΆΠ½Π° ΠΏΡ€ΠΈΡΡƒΡ‚ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Π² Π΄Ρ€ΡƒΠ³ΠΎΠΌ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π΅:

ΠœΡ‹ создали Π² классС прилоТСния ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ, которая ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π² сСбя интСрфСйс Π»ΠΎΠ³Π³Π΅Ρ€Π°, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΡ€ΠΈΡΡƒΡ‚ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹: log, error ΠΈ warn - сам Π»ΠΎΠ³Π³Π΅Ρ€ ΠΌΡ‹ Π½Π΅ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅ΠΌ, Π½ΠΎ Π² Π½Ρ‘ΠΌ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ описали Π² интСрфСйсС.

Π’Ρ‚ΠΎΡ€ΠΎΠΉ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ Π½Π°ΠΌ ΠΎ Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Π½Π°ΠΌ нСльзя ΠΏΡ€ΠΎΠΊΠΈΠ΄Ρ‹Π²Π°Ρ‚ΡŒ Π² Π±ΠΎΠ»Π΅Π΅ ΠΌΠ΅Π»ΠΊΠΈΠ΅ ΠΌΠΎΠ΄ΡƒΠ»ΠΈ (Ρ‚Π΅ ΠΆΠ΅ сСрвисы) ΠΌΠΎΠ΄ΡƒΠ»ΠΈ Π±ΠΎΠ»Π΅Π΅ высокого уровня: Нам нСльзя ΠΏΡ€ΠΎΠΊΠΈΠ΄Ρ‹Π²Π°Ρ‚ΡŒ инстанс app Π²Π½ΡƒΡ‚Ρ€ΡŒ Ρ‚ΠΎΠ³ΠΎ ΠΆΠ΅ exception, logger ΠΈΠ»ΠΈ router.

ΠšΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎ ΠΌΡ‹ ΠΈΠΌΠ΅Π΅ΠΌ:

  • ΠŸΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚ΡŒ
  • ΠŸΠ°Ρ‚Ρ‚Π΅Ρ€Π½, ΠΏΠΎ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌΡƒ эти ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ ΠΌΠΎΠΆΠ½ΠΎ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ
  • И сама рСализация

ΠŸΡ€ΠΈ рСгистрации прилоТСния наш класс А рСгистрируСтся Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅: ΠΌΡ‹ ΠΏΠΎΠ½ΠΈΠΌΠ°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ ΠΎΠ½ заинтсанциирован ΠΈ Ρ‡Ρ‚ΠΎ ΠΎΠ½ удовлСтворяСт ΠΊΠ°ΠΊΠΎΠΌΡƒ-Π»ΠΈΠ±ΠΎ интСрфСйсу Π’ΠΎ ΠΆΠ΅ самоС происходит с классом Π‘ ΠšΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ - это Ρ†Π΅Π½Ρ‚Ρ€Π°Π»ΡŒΠ½Π°Ρ Ρ‚ΠΎΡ‡ΠΊΠ° управлСния, которая Π·Π° нас создаёт наши классы, ΠΏΡ€ΠΈ этом ΠΎΠ½ ΠΏΠΎΠ½ΠΈΠΌΠ°Π΅Ρ‚, ΠΊΠ°ΠΊΠΈΠ΅ зависимости Π΅ΠΌΡƒ Π½ΡƒΠΆΠ½Ρ‹, создаёт эти зависимости ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘Ρ‚ ΠΈΡ… Π²Π½ΡƒΡ‚Ρ€ΡŒ. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ ΠΌΡ‹ избавляСмся ΠΎΡ‚ ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ создания Agregation Root - Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΎΠ½ создаётся автоматичСски ΠΈ Π΅Π³ΠΎ рСализация ΠΎΡ‚ нас скрыта, Ρ‡Ρ‚ΠΎ ΡƒΠΏΡ€ΠΎΡ‰Π°Π΅Ρ‚ наш DI, ΡƒΠΌΠ΅Π½ΡŒΡˆΠ°Ρ строчки Π½ΡƒΠΆΠ½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π°

Π’Π°ΠΊ ΠΆΠ΅ Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ рСализуСтся сСрвис Π»ΠΎΠΊΠ°Ρ‚ΠΎΡ€, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΠΌΡ‹ рСгистрируСм всС наши сСрвисы, Π° ΠΏΠΎΡ‚ΠΎΠΌ ΡƒΠΆΠ΅ ΠΌΠΎΠΆΠ΅ΠΌ Π²Ρ‹Ρ‚Π°Ρ‰ΠΈΡ‚ΡŒ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΉ инстанс этого сСрвиса, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π΅Π³ΠΎ Π² дальнСйшСм ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π’Π°ΠΊΠΎΠΉ ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½ Π½Π΅ стоит ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π² Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΉ Ρ€Π°Π±ΠΎΡ‚Π΅ - это просто ΡΡ…ΠΎΠΆΠ΅ΡΡ‚ΡŒ с ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΎΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Π² Π΄Π°Π½Π½ΠΎΠΉ систСмС - Π² нашСм случаС это ΠΏΠΎΠ»Π΅Π·Π½ΠΎ для тСстов ΠΈ запуска самого прилоТСния

069 Π”Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€Ρ‹

Π’ΡΡŽ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΎ Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€Π°Ρ… ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ Ρ‚ΡƒΡ‚: Π”Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€Ρ‹

Π‘Π°ΠΌ Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ прСдставляСт ΠΈΠ· сСбя ΠΎΠ±Ρ‘Ρ€Ρ‚ΠΊΡƒ, которая ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ Ρ‚ΠΎΡ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Π½Π°Π΄ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€ΠΎΠ²ΠΎΠ΄ΠΈΡ‚ΡŒΡΡ манипуляции ΠΈ Π΄Π°Π»Π΅Π΅ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΡ†ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ этого ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°

Π”Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ класса. Он ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π² сСбя Ρ‚Π°Ρ€Π³Π΅Ρ‚ - сам класс ΠΈ позволяСт Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΠΊΠ°ΠΊΠΈΠ΅-Π»ΠΈΠ±ΠΎ манипуляции Π½Π°Π΄ классом ΠΈΠ»ΠΈ ΠΆΠ΅ просто Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ вмСстС с классом.

function Component(target: Function) {
	console.log(target);
}
 
@Component
export class User {
	id: number;
 
	updateId(newId: number): number {
		this.id = newId;
		return this.id;
	}
}

И Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΌΡ‹ ΠΌΠΎΠ³Π»ΠΈ ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ свойства нашСго класса, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΈ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ Π΅Ρ‘ ΠΆΠ΅ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ, Π½ΠΎ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Π½Π½ΡƒΡŽ, ΠΊΠ°ΠΊ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ Π½ΠΈΠΆΠ΅ Π² ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅. Π’ΡƒΡ‚ ΠΌΡ‹ помСняли Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅Π΅ свойство класса Π½Π° ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½ΠΎΠ΅ Π² Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€. Π”Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ Ρ‚Π°ΠΊ ΠΆΠ΅ сСйчас записываСтся Π½Π΅ Ρ‡Π΅Ρ€Π΅Π· @Component, Π° Ρ‡Π΅Ρ€Π΅Π· @Component(Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅)

function Component(id: number) {
	console.log("init");
	return (target: Function) => {
		console.log("run");
		target.prototype.id = id;
	};
}
 
@Component(1)
export class User {
	id: number;
 
	updateId(newId: number): number {
		this.id = newId;
		return this.id;
	}
}
 
console.log(new User().id);

Π’Π°ΠΊ ΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΠ±ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Ρ‚ΡŒ наши ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ сразу Π² нСсколько Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ΠΎΠ². Π‘ΡƒΠ΄Π΅Ρ‚ ΠΈΠ΄Ρ‚ΠΈ порядок выполнСния снизу Π²Π²Π΅Ρ€Ρ… Π² случаС классов. Π’ ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Ρ… случаях - свСрху Π²Π½ΠΈΠ·

function Component(id: number) {
	console.log("init Component");
	return (target: Function) => {
		console.log("run Component");
		target.prototype.id = id;
	};
}
 
function Logger() {
	console.log("init Logger");
	return (target: Function) => {
		console.log("run Logger");
	};
}
 
@Logger()
@Component(1)
export class User {
	id: number;
 
	updateId(newId: number): number {
		this.id = newId;
		return this.id;
	}
}
 
console.log(new User().id);

Π”Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ². Π’Π°ΠΊ ΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ вовсС ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ Π»ΠΎΠ³ΠΈΠΊΡƒ Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² Π²Π½ΡƒΡ‚Ρ€ΠΈ классов. Π”Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ позволяСт ΡΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΠΈΠ·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΡƒΡŽ Ρ€Π°Π±ΠΎΡ‚Ρƒ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° ΠΈ просто Π΅Ρ‘ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ, Π»ΠΈΠ±ΠΎ ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ вовсС.

 
// ΠΊΠΎΠ΄ ...
 
// это Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°
function Method(
	// сам ΠΎΠ±ΡŠΠ΅ΠΊΡ‚
	target: Object,
	// имя ΠΌΠ΅Ρ‚ΠΎΠ΄Π°
	propertyKey: string,
	propertyDescriptor: PropertyDescriptor
) {
	// Ρ‚ΡƒΡ‚ Π²Ρ‹Π²ΠΎΠ΄ΠΈΠΌ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°
	console.log(propertyKey);
	// Ρ‚ΡƒΡ‚ ΠΌΡ‹ сохраняСм старый ΠΌΠ΅Ρ‚ΠΎΠ΄
	const oldValue = propertyDescriptor.value;
	// Ρ‚ΡƒΡ‚ ΡƒΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ
	propertyDescriptor.value = function (...args: unknown[]) {
		// oldValue(); // Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ исходный ΠΌΠ΅Ρ‚ΠΎΠ΄
 
		// ΡƒΠΌΠ½ΠΎΠΆΠΈΡ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹ΠΉ id Π½Π° 10, Ссли ΠΎΠ½ являСтся числом
		if (typeof args[0] === "number") {
			return args[0] * 10;
		}
		return args;
	};
}
 
@Logger()
@Component(1)
export class User {
	id: number;
 
	@Method
	updateId(newId: number): number {
		this.id = newId;
		return this.id;
	}
}
 
console.log(new User().id);
console.log(new User().updateId(2)); // 20

Π’ΡƒΡ‚ ΡƒΠΆΠ΅ прСдставлСна Ρ€Π°Π±ΠΎΡ‚Π° всСх Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ΠΎΠ², Π²ΠΊΠ»ΡŽΡ‡Π°Ρ Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€Ρ‹ свойства ΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° ΠΌΠ΅Ρ‚ΠΎΠ΄Π°

ΠΏΠΎΠ»Π½Ρ‹ΠΉ листинг

// Π”Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ класса
function Component(id: number) {
	console.log("init Component");
 
	// Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ свойства класса, Π½ΡƒΠΆΠ½ΠΎ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ этого класса
	return (target: Function) => {
		console.log("run Component");
		// ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘ΠΌ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π²ΠΎ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅Π΅ свойство класса
		target.prototype.id = id;
	};
}
 
// это Π²Ρ‚ΠΎΡ€ΠΎΠΉ Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ класса - Π»ΠΎΠ³Π³Π΅Ρ€
function Logger() {
	console.log("init Logger");
 
	// Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ сам класс ΠΈ Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ Π»ΠΎΠ³
	return (target: Function) => {
		console.log("run Logger");
	};
}
 
// это Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°
function Method(
	// сам ΠΎΠ±ΡŠΠ΅ΠΊΡ‚
	target: Object,
	// имя ΠΌΠ΅Ρ‚ΠΎΠ΄Π°
	propertyKey: string,
	propertyDescriptor: PropertyDescriptor
) {
	// Ρ‚ΡƒΡ‚ Π²Ρ‹Π²ΠΎΠ΄ΠΈΠΌ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°
	console.log(propertyKey);
	// Ρ‚ΡƒΡ‚ ΠΌΡ‹ сохраняСм старый ΠΌΠ΅Ρ‚ΠΎΠ΄
	const oldValue = propertyDescriptor.value;
	// Ρ‚ΡƒΡ‚ ΡƒΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ
	propertyDescriptor.value = function (...args: unknown[]) {
		// oldValue(); // Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ исходный ΠΌΠ΅Ρ‚ΠΎΠ΄
 
		// ΡƒΠΌΠ½ΠΎΠΆΠΈΡ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹ΠΉ id Π½Π° 10, Ссли ΠΎΠ½ являСтся числом
		if (typeof args[0] === "number") {
			return args[0] * 10;
		}
		return args;
	};
}
 
// Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ для свойства класса
function Prop(target: Object, propertyKey: string) {
	let value: number;
 
	// Π³Π΅Ρ‚Ρ‚Π΅Ρ€ для ΠΏΡ€ΠΎΠΏΠ΅Ρ€Ρ‚ΠΈ
	const getter = () => {
		console.log("get");
		return value;
	};
 
	// сСттСр для ΠΏΡ€ΠΎΠΏΠ΅Ρ€Ρ‚ΠΈ
	const setter = (newValue: number) => {
		console.log("set");
		value = newValue;
	};
 
	// пСрСопрСдСляСм Π³Π΅Ρ‚Ρ‚Π΅Ρ€ ΠΈ сСттСр для значСния
	Object.defineProperty(target, propertyKey, {
		get: getter,
		set: setter,
	});
}
 
// Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ для ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ
function Param(
	target: Object,
	propertyKey: string,
	// индСкс ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ³ΠΎ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ
	index: number
) {
	console.log(propertyKey, index);
}
 
@Logger() // срабатываСт Π²Ρ‚ΠΎΡ€Ρ‹ΠΌ
@Component(1) // срабатываСт ΠΏΠ΅Ρ€Π²Ρ‹ΠΌ
export class User {
	// Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ свойства
	@Prop id: number;
 
	// Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° + Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° ΠΌΠ΅Ρ‚ΠΎΠ΄Π°
	@Method
	updateId(@Param newId: number): number {
		this.id = newId;
		return this.id;
	}
}
 
console.log(new User().id);
console.log(new User().updateId(2)); // 20

Π­Ρ‚ΠΎ Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ для свойства класса

А Ρ‚ΡƒΡ‚ Ρ€Π°Π±ΠΎΡ‚Π° Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€Π° для Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π° ΠΌΠ΅Ρ‚ΠΎΠ΄Π°

070 Metadata Reflection

ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΡΡƒΡ‰Π΅ΡΡ‚Π²Π»ΡΡ‚ΡŒ Ρ…Ρ€Π°Π½Π΅Π½ΠΈΠ΅ ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ… Π½Π°ΡˆΠΈΡ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Reflect. Π’ Π½Π΅ΠΉ присутствуСт ΠΌΠ΅Ρ‚ΠΎΠ΄ defineMetadata(), которая позволяСт ΠΏΡ€ΠΈΡΠ²ΠΎΠΈΡ‚ΡŒ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΉ ΠΊΠ»ΡŽΡ‡ с ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΌ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ ΠΊ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠΌΡƒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρƒ. Π’Π°ΠΊ ΠΆΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠΌ getMetadata() ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎ этому ΠΊΠ»ΡŽΡ‡Ρƒ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΌΠ΅Ρ‚Π°ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΏΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρƒ

Π’Π°ΠΊ ΠΌΡ‹ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ…

npm i reflect-metadata

Π’Π°ΠΊ выглядит синтаксис создания ΠΈ получСния ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ… для ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°

import "reflect-metadata";
 
function Test(target: Function) {
	// сохранСниС ΠΌΠ΅Ρ‚Π°Π΄Π°Ρ‚Ρ‹ ΠΏΠΎΠ΄ ΠΊΠ»ΡŽΡ‡ΠΎΠΌ "a" Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ 1 ΠΏΠΎΠ΄ нашим классом
	Reflect.defineMetadata("a", 1, target);
 
	// ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΠΎΠ΄ ΠΊΠ»ΡŽΡ‡ΠΎΠΌ "a" ΠΎΡ‚ нашСго класса
	const meta = Reflect.getMetadata("a", target);
 
	console.log(meta);
}
 
@Test
export class C {}

Π’ΠΊΡƒΠΏΠ΅ с этой настройкой компилятора Π’Π‘, Ρƒ нас Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π½ΠΎΡΠΈΡ‚ΡŒΡΡ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Ρ‚ΠΈΠΏΠΎΠ² ΠΈ Π² наш Ρ€Π°Π½Ρ‚Π°ΠΉΠΌ (Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ послС компиляции)

tsconfig.json

"emitDecoratorMetadata": true,

Ну ΠΈ сСйчас Π½ΡƒΠΆΠ½ΠΎ ΠΎΠ±ΡŠΡΡΠ½ΠΈΡ‚ΡŒ связь Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ΠΎΠ² ΠΈ ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ…. Π”Π΅Π»ΠΎ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€Ρ‹ ΠΏΠΎΠ΄ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΉ инстанс класса ΠΈ Π΄Π΅Π»Π°Ρ‚ΡŒ DI с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π²Ρ‹Π·ΠΎΠ²Π° Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΠ½Π΄ΠΆΠ΅ΠΊΡ‚ΠΈΡ‚ инстанс класса ΠΏΡ€ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ конструктором Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ класса. Π’ΠΎ Π΅ΡΡ‚ΡŒ ΠΈΠ΄Ρ‘Ρ‚ связываниС классов Π΄Ρ€ΡƒΠ³ с Π΄Ρ€ΡƒΠ³ΠΎΠΌ Ρ‡Π΅Ρ€Π΅Π· ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Π΅, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡΠΎΡ…Ρ€Π°Π½ΡΡŽΡ‚ΡΡ ΠΏΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€Π°, Π²Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌΠΎΠ³ΠΎ ΠΏΠΎΠ΄ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ конструктора ΠΈΠ»ΠΈ ΠΏΠΎΠ΄ класс.

import "reflect-metadata";
 
// Pseudocode
 
function Injectable(key: string) {
	return (target: Function) => {
		Reflect.defineMetadata(key, 1, target);
		const meta = Reflect.getMetadata(key, target);
		console.log(meta);
	};
}
 
function Inject(key: string) {}
 
function Prop(target: Object, name: string) {}
 
// ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡Π°Π΅ΠΌ класс "C"
@Injectable("C")
export class C {
	@Prop prop: number;
}
 
// ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡Π°Π΅ΠΌ класс "D"
@Injectable("D")
export class D {
	// Ρ‚ΡƒΡ‚ ΠΈΠ΄Ρ‘Ρ‚ связываниС инстанса класса "C" с ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ пСрСдаётся Π² конструктор
	constructor(@Inject('C') c: C) {}
}

071 ВнСдряСм InversifyJS

Π’ ΠΏΠ΅Ρ€Π²ΡƒΡŽ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ, Π½ΡƒΠΆΠ½ΠΎ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ inversify Π² ΠΏΡ€ΠΎΠ΅ΠΊΡ‚

npm i inversify

Π’ΡƒΡ‚ Π±ΡƒΠ΄ΡƒΡ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒΡΡ символы, ΠΏΠΎ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠΈΡΡ…ΠΎΠ΄ΠΈΡ‚ΡŒ связываниС Π½Π°ΡˆΠΈΡ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°

types.ts

export const TYPES = {
	Application: Symbol.for('Application'),
	ILogger: Symbol.for('ILogger'),
	UserController: Symbol.for('UserController'),
	ExceptionFilter: Symbol.for('ExceptionFilter'),
};

Π”Π°Π»Π΅Π΅ Π² основном Ρ„Π°ΠΉΠ»Π΅ прилоТСния ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π½Π°ΠΊΠΎΠ½Π΅Ρ† ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€, Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠΈΡΡ…ΠΎΠ΄ΠΈΡ‚ΡŒ связываниС класса с Π΅Π³ΠΎ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ΠΎΠΌ (Π² качСствС ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ выступаСт символ TYPES)

main.ts

// ΠšΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ - это ΠΊΠΎΡ€ΠΎΠ±ΠΊΠ°, Π² ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π²ΠΊΠ»Π°Π΄Ρ‹Π²Π°Ρ‚ΡŒ Π±ΠΈΠ½Π΄ΠΈΠ½Π³ΠΈ символов Π½Π° ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΡƒΡŽ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ, Π° ΠΏΠΎΡ‚ΠΎΠΌ Π±ΡƒΠ΄Π΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ
const appContainer = new Container();
 
// Π’ΡƒΡ‚ ΡƒΠΆΠ΅ Π±ΡƒΠ΄ΡƒΡ‚ Π»Π΅ΠΆΠ°Ρ‚ΡŒ Π±ΠΈΠ½Π΄ΠΈΠ½Π³ΠΈ Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ
// Π’ΡƒΡ‚ ΠΌΡ‹ ΡƒΠΊΠ°Π·Π°Π»ΠΈ, Ρ‡Ρ‚ΠΎ для интСрфСйса ILogger Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ LoggerService Ρ‡Π΅Ρ€Π΅Π· символ TYPES.ILogger
appContainer.bind<ILogger>(TYPES.ILogger).to(LoggerService);
appContainer.bind<IExceptionFilter>(TYPES.ExceptionFilter).to(ExceptionFilter);
appContainer.bind<UserController>(TYPES.UserController).to(UserController);
appContainer.bind<App>(TYPES.Application).to(App);
 
// Π’ΡƒΡ‚ ΡƒΠΆΠ΅ ΠΌΡ‹ достаём ΠΈΠ· ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π° наш ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ App
const app = appContainer.get<App>(TYPES.Application);
 
app.init();
 
export { app, appContainer };

Π’Π°ΠΊ ΠΆΠ΅ для Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ связывания, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ΄ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Π² качСствС Π΄ΠΆΠ΅Π½Π΅Ρ€ΠΈΠΊΠ° Π½Π΅ интСрфСйс, Π° сам класс, Ссли ΠΌΡ‹ ΠΏΠΎΠ΄Ρ€Π°Π·ΡƒΠΌΠ΅Π²Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹ Π±ΡƒΠ΄ΡƒΡ‚ ΠΈΠ΄Ρ‚ΠΈ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ.

// Π’ΡƒΡ‚ ΡƒΠΆΠ΅ вмСсто интСрфСйса ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΡƒΡŽ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ ExceptionFilter для связывания
appContainer
	.bind<ExceptionFilter>(TYPES.ExceptionFilter)
	.to(ExceptionFilter);

Π”Π°Π»Π΅Π΅ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ произвСсти ΠΈΠ½ΠΆΠ΅ΠΊ всСх зависимостСй ΠΎΡ‚ основного прилоТСния, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ½ΠΈ ΠΏΠΎΠΏΠ°Π»ΠΈ Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ ΠΈ Π΄ΠΎ Π½ΠΈΡ… ΠΌΠΎΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ Π΄ΠΎΡΡ‚ΡƒΡ‡Π°Ρ‚ΡŒΡΡ Π²ΠΎ врСмя использования ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π° инвСрсифая

logger.service.ts

// Π΄Π°Π½Π½Ρ‹ΠΉ Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ»ΠΎΠΆΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹ΠΉ класс Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€
// Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ ΠΏΠΎΠΊΠ° ΠΌΡ‹ Π½Π΅ ΠΏΠ΅Ρ€Π΅Π΄Π°Π»ΠΈ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹, Ρ‚ΠΎ ΠΌΡ‹ Π½Π΅ Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ Π½ΠΈΠΊΠ°ΠΊΠΎΠΉ связи с символами
@injectable()
export class LoggerService implements ILogger {
	public logger: Logger<string>;
 
	// code ...

Π’Π°ΠΊ ΠΆΠ΅ Π½ΡƒΠΆΠ½ΠΎ произвСсти ΠΈΠ½ΠΆΠ΅ΠΊΡ‚ всСх зависимостСй ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ доступны Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°

exception.filter.ts

import 'reflect-metadata';
 
@injectable()
export class ExeptionFilter implements IExeptionFilter {
	// inject - это Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ Π·Π°ΠΈΠ½Π΄ΠΆΠ΅ΠΊΡ‚ΠΈΡ‚ΡŒ
	constructor(@inject(TYPES.ILogger) private logger: ILogger) { }
	// code...

Π’Π°ΠΊ ΠΆΠ΅ Π½ΡƒΠΆΠ½ΠΎ ΡƒΠΏΠΎΠΌΡΠ½ΡƒΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΈΠΌΠ΅Π½Π° ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² ΠΈ классов Π½Π΅ стоит ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΡΡ‚ΡŒ, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΎΠ½ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΠΎΠ²Π°Ρ‚ΡŒ Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅

users.controller.ts

@injectable()
export class UserController extends BaseController {
	// мСняСм имя logger Π½Π° loggerService, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ Π±Ρ‹Π»ΠΎ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΠΎΠ² Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°
	constructor(@inject(TYPES.ILogger) private loggerService: ILogger) {
		super(loggerService);
		this.bindRoutes([
			{
				path: "/register",
				method: "post",
				func: this.register,
			},
			{
				path: "/login",
				method: "post",
				func: this.login,
			},
		]);
	}
 
	// code ...

base.controller.ts

// этот класс Π½ΡƒΠΆΠ½ΠΎ Ρ‚Π°ΠΊ ΠΆΠ΅ Π·Π°ΠΈΠ½Π΄ΠΆΠ΅ΠΊΡ‚ΠΈΡ‚ΡŒ, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΈΠΌ Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅Ρ‚ΡΡ users.controller
@injectable()
export abstract class BaseController {
	private readonly _router: Router;
 
	constructor(private logger: ILogger) {
		this._router = Router();
	}
 
	// code ...

И Π² основном классС прилоТСния Π½ΡƒΠΆΠ½ΠΎ Ρ‚Π°ΠΊ ΠΆΠ΅ Π·Π°ΠΈΠ½ΠΆΠ΅ΠΊΡ‚ΠΈΡ‚ΡŒ всС ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ ΠΈ сам класс

app.ts

// Π΄Π΅Π»Π°Π΅ΠΌ основной класс Ρ‚ΠΎΠΆΠ΅ внСдряСмым
@injectable()
export class App {
	app: Express;
	server: Server;
	port: number;
 
	constructor(
		// И Ρ‚ΡƒΡ‚ мСняСм всС наши зависимости с использованиСм дСкорирования
		@inject(TYPES.ILogger) private logger: ILogger,
		@inject(TYPES.UserController) private userController: UserController,
		@inject(TYPES.ExceptionFilter) private exceptionFilter: ExceptionFilter
	) {
		this.app = express();
		this.port = 8000;
	}
 
	// code ...

common > base.controller.ts

export abstract class BaseController {
	private readonly _router: Router;
 
	// Π—Π΄Π΅ΡΡŒ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ интСрфСйс ILogger
	constructor(private logger: ILogger) {
		this._router = Router();
	}
 
	// code ...

Π”Π°Π»Π΅Π΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ всё Π·Π°Ρ€Π°Π±ΠΎΡ‚Π°Π»ΠΎ, Π½ΡƒΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹ΠΉ ΠΈΠΌΠΏΠΎΡ€Ρ‚ Π²ΠΎ всС Ρ„Π°ΠΉΠ»Ρ‹, Π² ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π±Ρ‹Π» использован inject ΠΈΠ· Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ inversify

import 'reflect-metadata';

И Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ±Π΅Π΄ΠΈΡ‚ΡŒΡΡ, Ρ‡Ρ‚ΠΎ нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚.

Π˜Ρ‚ΠΎΠ³:

  • Π’ ΠΈΡ‚ΠΎΠ³Π΅ ΠΌΡ‹ Π·Π°ΠΌΠ΅Π½ΠΈΠ»ΠΈ наш DI Π½Π° Ρ€ΡƒΡ‡Π½ΠΎΠΉ Π±ΠΈΠ½Π΄ΠΈΠ½Π³ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Π°.
  • ΠžΡΠ½ΠΎΠ²Π½Ρ‹ΠΌ плюсом Ρ‚Π°ΠΊΠΎΠ³ΠΎ подходя являСтся Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π² любой ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ любой инстанс ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Ρ‡Π΅Ρ€Π΅Π· get.
  • Если Ρƒ нас Π³Π΄Π΅-Ρ‚ΠΎ появится Π½ΠΎΠ²Ρ‹ΠΉ ндТСктэбл, Ρ‚ΠΎ Π½Π°ΠΌ Π½Π΅ придётся Π΅Π³ΠΎ ΠΏΡ€ΠΎΠΊΠΈΠ΄Ρ‹Π²Π°Ρ‚ΡŒ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ. Нам Π½ΡƒΠΆΠ½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π· ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ bind ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π° ΠΈ Π² Ρ‚ΠΎΠΌ мСстС, Π³Π΄Π΅ Π½ΡƒΠΆΠ½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠ΄ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Ρ‚ΠΈΠΏ, ΠΌΡ‹ смоТСм Π΅Π³ΠΎ ΠΏΠΎΠ΄ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· @inject(TYPES.Ρ‚ΠΈΠΏ)
  • Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ позволяСт Π½Π°ΠΌ Π»Π΅Π³ΠΊΠΎ ΠΌΠ΅Π½ΡΡ‚ΡŒ сСрвисы - достаточно просто ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ Π΅Π³ΠΎ Π² .to(БСрвис) ΠΈ Ρƒ нас всё Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ.

072 Π£ΠΏΡ€Π°ΠΆΠ½Π΅Π½ΠΈΠ΅ - Π£Π»ΡƒΡ‡ΡˆΠ°Π΅ΠΌ DI

Π”Π°Π»Π΅Π΅ нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ сильно Ρ€Π°Π·Ρ€Π°ΡΡ‚ΠΈΡΡŒ ΠΈ количСство Π±ΠΈΠ½Π΄ΠΈΠ½Π³ΠΎΠ² Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΡ‚ΡŒ Π·Π° Ρ€Π°ΠΌΠΊΠΈ 30 ΠΈ 40 ΡˆΡ‚ΡƒΠΊ. Для Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ с большим количСством Π±ΠΈΠ½Π΄ΠΈΠ½Π³ΠΎΠ², которая Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ Π²ΠΎ врСмя Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ, Π±Ρ‹Π» ΠΏΡ€ΠΈΠ΄ΡƒΠΌΠ°Π½ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°

main.ts

appContainer.bind<ILogger>(TYPES.ILogger).to(LoggerService);
appContainer.bind<IExeptionFilter>(TYPES.ExeptionFilter).to(ExeptionFilter);
appContainer.bind<UserController>(TYPES.UserController).to(UserController);
appContainer.bind<App>(TYPES.Application).to(App);

Π’ΠΎΡ‚ Ρ‚Π°ΠΊ выглядит обновлённая вСрсия ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° с собранными Π±ΠΈΠ½Π΄ΠΈΠ½Π³Π°ΠΌΠΈ. Π’Π°ΠΊ ΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡΠΊΡΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ эти Π±ΠΈΠ½Π΄ΠΈΠ½Π³ΠΈ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΠΈΡ… Π² ΠΎΠ΄Π½ΠΎΠΌ мСстС, Π° Ρ€Π°ΡΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΏΠΎ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρƒ ΠΈ ΡƒΠ΄ΠΎΠ±Π½ΠΎ Ρ€Π°Π·Π΄Π΅Π»ΡΡ‚ΡŒ ΠΈΡ…, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π² Π±ΡƒΠ΄ΡƒΡ‰Π΅ΠΌ ΠΌΠΎΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ ΡƒΠ΄ΠΎΠ±Π½ΠΎ Ρ€Π°Π·Π»ΠΈΡ‡Π°Ρ‚ΡŒ ΠΈΡ… ΠΈ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ

main.ts

// Π­Ρ‚ΠΎ функция, которая Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΠ²Π΅Ρ€ΡˆΠ°Ρ‚ΡŒ Π±ΠΈΠ½Π΄ΠΈΠ½Π³ΠΈ инвСрсифая
export const appBindings = new ContainerModule((bind: interfaces.Bind) => {
	bind<ILogger>(TYPES.ILogger).to(LoggerService);
	bind<IExeptionFilter>(TYPES.ExeptionFilter).to(ExeptionFilter);
	bind<UserController>(TYPES.UserController).to(UserController);
	bind<App>(TYPES.Application).to(App);
});
 
function bootstrap() {
	const appContainer = new Container();
 
	// ΡƒΠΆΠ΅ Ρ‚ΡƒΡ‚ ΠΌΡ‹ просто Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ всС Π±ΠΈΠ½Π΄ΠΈΠ½Π³ΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π»ΠΈ Ρ€Π°Π½Π΅Π΅
	appContainer.load(appBindings);
 
	const app = appContainer.get<App>(TYPES.Application);
	app.init();
 
	// Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ сформированный ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ ΠΈ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅
	return { app, appContainer };
}
 
// экспортируСм ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅, ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹Π΅ ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ
export const { app, appContainer } = bootstrap();

И Π΄Π°Π»Π΅Π΅ Π½ΡƒΠΆΠ½ΠΎ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΡƒΠ»ΡƒΡ‡ΡˆΠΈΡ‚ΡŒ наш DI ΠΈ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ интСрфСйс для ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Π° ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ. Он Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΠΌΠ΅Ρ‚ΡŒ Π»ΠΎΠ³ΠΈΠ½ ΠΈ Ρ€Π΅Π³ΠΈΡΡ‚Ρ€Π°Ρ†ΠΈΡŽ.

users.controller.interface.ts

import { NextFunction, Request, Response } from 'express';
 
export interface IUserController {
	login: (req: Request, res: Response, next: NextFunction) => void;
	register: (req: Request, res: Response, next: NextFunction) => void;
}

Π’ самом ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Π΅ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ вмСстС с экстСндом ΠΎΡ‚ Π±Π°Π·ΠΎΠ²ΠΎΠ³ΠΎ модуля Π΅Ρ‰Ρ‘ ΠΈ Π·Π°ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΎΡ‚ интСрфСйса. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΌΠΎΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΈ Ρ‚ΠΎ, ΠΈ Ρ‚ΠΎ, Π½ΡƒΠΆΠ½ΠΎ сначала произвСсти extends, Π° ΡƒΠΆΠ΅ ΠΏΠΎΡ‚ΠΎΠΌ implements

users.controller.ts

// imports...
import { IUserController } from './users.controller.interface';
 
@injectable()
export class UserController extends BaseController implements IUserController {
	constructor(
		@inject(TYPES.ILogger) private loggerService: ILogger
	) {
		super(loggerService);
		this.bindRoutes([
			{ path: '/register', method: 'post', func: this.register },
			{ path: '/login', method: 'post', func: this.login },
		])
	}
 
	login(req: Request, res: Response, next: NextFunction) {
		next(new HTTPError(401, 'ошибка Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ', 'login'));
	}
 
	register(req: Request, res: Response, next: NextFunction) {
		this.ok(res, 'register');
	}
}