跳到主要内容

Nestjs快速上手系列一

3 分钟阅读

本系列介绍 NestJS 入门必备:CLI 常用命令、IoC/DI 思想,以及 TypeScript 装饰器在 Nest 中的用法。

📝 概述

本文包含三部分:Nest CLI 常用命令(新建项目、生成模块/控制器/服务等)、IoC 与 DI(控制反转与依赖注入的概念与代码示例)、装饰器(方法/类/属性装饰器及在 Nest 中的对应关系)。掌握这些后,可以更顺畅地阅读和编写 Nest 代码。


一、Nest CLI 常用命令

项目相关

命令说明
nest new 项目名新建项目
nest start启动(开发模式,默认)
nest start --watch监听文件变化并自动重启
nest build构建生产包

生成代码(最常用)

命令说明
nest g resource 名称生成完整 CRUD 模块(controller + service + module + dto)
nest g module 名称生成模块
nest g controller 名称生成控制器
nest g service 名称生成服务

示例:

nest g resource user          # 生成 user 模块,会问是否要 CRUD
nest g resource post --no-spec # 不生成测试文件
nest g module auth
nest g controller auth
nest g service auth

其他

命令说明
nest g guard 名称守卫
nest g pipe 名称管道
nest g middleware 名称中间件
nest info查看 Nest 与依赖版本

二、IoC(控制反转)与 DI(依赖注入)

IoC 与 DI 本质是一体两面:IoC 是一种思想(控制权交给容器),DI 是 IoC 的一种具体实现(通过注入依赖)。

一句话:DI 的作用是把依赖的创建和保管交给「容器」统一维护,从而让类与依赖解耦。

没有 DI:自己创建依赖(紧耦合)

// B 自己 new 了 A 和 C → 强依赖具体实现,难测试、难替换
class A {
name: string;
constructor(name: string) {
this.name = name;
}
}

class C {
name: string;
constructor(name: string) {
this.name = name;
}
}

class B_WithoutDI {
a: A;
c: C;
constructor() {
this.a = new A('1'); // 控制权在 B 内部
this.c = new C('2');
}
}

有 DI:依赖由外部注入(解耦)

// 「容器」负责创建和保管实例,需要时再取出来 → 控制权在容器 = IoC
class Container {
modules: Record<string, unknown>;

constructor() {
this.modules = {};
}

provide(key: string, instance: unknown) {
this.modules[key] = instance;
}

get<T = unknown>(key: string): T {
return this.modules[key] as T;
}
}

// B 不再 new A/C,只声明「我需要 a 和 c」,由容器注入 → 这就是 DI
class B_WithDI {
a: A;
c: C;
constructor(container: Container) {
this.a = container.get<A>('a'); // 依赖从外部注入
this.c = container.get<C>('c');
}
}

小结:

  • DI 的好处:解耦、易测、易扩展、职责更清晰。
  • 前端类比:不自己造依赖、也不靠一层层 props 传,而是像 Context / provide-inject 那样「声明需要什么,由外层/容器提供」;Nest 的 DI 是同一思想在后端:容器负责创建和注入,你只在构造函数里「声明要什么」。

三、装饰器

装饰器(Decorator) 是一个函数,用来「标注」类、方法、属性或参数,在类定义时执行,用于改变类或成员的行为。在 TypeScript 中有四种:类装饰器、方法装饰器、属性装饰器、参数装饰器

方法装饰器(MethodDecorator)

签名:(target, key, descriptor) => void | PropertyDescriptor

  • target:类的原型(实例方法)或构造函数(静态方法)
  • key:方法名(string | symbol)
  • descriptor:该方法的属性描述符(value、writable、enumerable 等)
const currency: MethodDecorator = (
target: object,
key: string | symbol,
descriptor: PropertyDescriptor,
) => {
console.log('target(原型):', target);
console.log('key(方法名):', key);
console.log('descriptor(描述符):', descriptor);
return descriptor;
};

class Dog {
public name: string;
constructor() {
this.name = '';
}

@currency
getName(name: string, age: number): string {
return `${this.name}-${name}-${age}`;
}
}

const x = new Dog();
x.getName('a', 1);

方法装饰器常见用法:包装原方法

function log(
_target: object,
key: string | symbol,
descriptor: PropertyDescriptor,
): void {
const original = descriptor.value as (...args: unknown[]) => unknown;
descriptor.value = function (this: unknown, ...args: unknown[]): unknown {
console.log(`调用 ${String(key)}`, args);
return original.apply(this, args) as unknown;
};
}

class Service {
@log
greet(msg: string) {
return `Hello, ${msg}`;
}
}

const s = new Service();
s.greet('Nest'); // 控制台: 调用 greet ['Nest'],返回值: 'Hello, Nest'

类装饰器(ClassDecorator)

参数只有一个:target 是构造函数本身。

function Component(constructor: new (...args: unknown[]) => object) {
console.log('类装饰器:', constructor.name);
}

@Component
class App {}

属性装饰器(PropertyDecorator)

参数:(target 原型, key 属性名),没有 descriptor(需配合 reflect-metadata 等做更多事)。

function Default(value: string) {
return (target: object, key: string | symbol) => {
(target as Record<string | symbol, string>)[key] = value;
};
}

class Config {
@Default('dev')
env!: string;
}

和 Nest 的对应关系

Nest 里大量用装饰器做「声明式」配置,例如:

装饰器类型作用
@Controller('user')类装饰器标记为控制器并指定路由前缀
@Get()方法装饰器标记为 GET 且绑定到对应路径
@Injectable()类装饰器标记可被 DI 注入
@Body() / @Query()参数装饰器标记参数从哪来(body/query)

🎯 总结

  • Nest CLInest g resource/module/controller/service 等可快速生成骨架代码。
  • IoC/DI:把依赖的创建与保管交给容器,类只声明「需要什么」,实现解耦与易测。
  • 装饰器:TS 的类/方法/属性/参数装饰器在 Nest 中对应 @Controller@Get@Injectable@Body 等,用于声明式配置。

下一期可以继续写 Nest 的模块、控制器与服务的实际用法。

Loading Comments...