1. 為什麼 TypeScript 對 NestJS 很重要?
NestJS 完全使用 TypeScript 構建,並充分利用 TypeScript 的高級功能,例如 裝飾器, 元數據反映, 泛型。了解 TypeScript 將幫助您更有效地使用 NestJS。
2. 裝飾器-NestJS的核心
裝飾器是 NestJS 最常用的 TypeScript 功能。他們是 特殊功能 附加到類別、方法、屬性或參數以新增元資料。
類別裝飾器
// Class Decorator
function Controller(prefix: string) {
return function (target: Function) {
Reflect.defineMetadata('prefix', prefix, target);
};
}
@Controller('/users')
class UsersController {
// NestJS tự biết controller này handle route /users
}
方法裝飾器
// Method Decorator
function Log(target: any, key: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling ${key} with args:`, args);
const result = original.apply(this, args);
console.log(`Result:`, result);
return result;
};
}
class UserService {
@Log
findUser(id: number) {
return { id, name: 'John' };
}
}
參數裝飾器
// Trong NestJS, bạn sẽ gặp:
@Get(':id')
findOne(
@Param('id') id: string, // Parameter decorator
@Query('include') include: string, // Parameter decorator
@Body() body: CreateUserDto, // Parameter decorator
) {
// ...
}
裝飾器組合
// Kết hợp nhiều decorators
function Auth(...roles: string[]) {
return applyDecorators(
UseGuards(AuthGuard('jwt'), RolesGuard),
Roles(...roles),
ApiBearerAuth(),
);
}
@Auth('admin')
@Get('admin/dashboard')
getDashboard() { ... }
3. 介面和型別別名
// Interface — mở rộng được, dùng cho object shapes
interface User {
id: number;
name: string;
email: string;
role: UserRole;
createdAt: Date;
}
// Extending interfaces
interface AdminUser extends User {
permissions: string[];
lastLogin: Date;
}
// Type alias — linh hoạt hơn, dùng cho unions, tuples
type UserRole = 'admin' | 'editor' | 'viewer';
type ApiResponse<T> = {
data: T;
meta: { total: number; page: number };
};
// Trong NestJS, dùng interface cho DTOs shape, class cho validation
4. 泛型-程式碼重用
// Generic function
function wrapResponse<T>(data: T): ApiResponse<T> {
return { data, meta: { total: 1, page: 1 } };
}
// Generic class — pattern phổ biến trong NestJS Repository
class BaseRepository<T> {
private items: T[] = [];
findAll(): T[] {
return this.items;
}
findById(id: number): T | undefined {
return this.items.find((item: any) => item.id === id);
}
create(item: T): T {
this.items.push(item);
return item;
}
}
// Sử dụng
class UserRepository extends BaseRepository<User> {
findByEmail(email: string): User | undefined {
return this.findAll().find(u => u.email === email);
}
}
// Generic constraints
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
5. 枚舉
// String enum — dùng nhiều trong NestJS
enum UserRole {
Admin = 'ADMIN',
Editor = 'EDITOR',
Viewer = 'VIEWER',
}
// Const enum — tối ưu performance
const enum HttpStatus {
OK = 200,
Created = 201,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404,
}
// Sử dụng trong NestJS
@Roles(UserRole.Admin)
@Get('admin')
adminOnly() { ... }
6. 常用實用程式類型
interface User {
id: number;
name: string;
email: string;
password: string;
avatar?: string;
}
// Partial — tất cả fields optional (dùng cho Update DTO)
type UpdateUserDto = Partial<User>;
// Pick — chọn một số fields
type UserPublicInfo = Pick<User, 'id' | 'name' | 'avatar'>;
// Omit — loại bỏ fields (ẩn password)
type UserResponse = Omit<User, 'password'>;
// Record — key-value mapping
type UserPermissions = Record<string, boolean>;
// Required — tất cả fields bắt buộc
type StrictUser = Required<User>;
// NestJS PartialType, PickType, OmitType từ @nestjs/mapped-types
// làm tương tự nhưng giữ validation decorators
import { PartialType, OmitType } from '@nestjs/mapped-types';
class UpdateUserDto extends PartialType(CreateUserDto) {}
class UserResponseDto extends OmitType(CreateUserDto, ['password']) {}
7. 類型保護與縮小
// typeof guard
function processInput(input: string | number) {
if (typeof input === 'string') {
return input.toUpperCase(); // TypeScript biết đây là string
}
return input.toFixed(2); // TypeScript biết đây là number
}
// instanceof guard
class HttpException {
constructor(public message: string, public status: number) {}
}
class NotFoundException extends HttpException {
constructor(resource: string) {
super(`${resource} not found`, 404);
}
}
function handleError(error: Error | HttpException) {
if (error instanceof HttpException) {
return { statusCode: error.status, message: error.message };
}
return { statusCode: 500, message: 'Internal Server Error' };
}
// Custom type guard
interface AdminUser { role: 'admin'; permissions: string[] }
interface RegularUser { role: 'user'; subscription: string }
function isAdmin(user: AdminUser | RegularUser): user is AdminUser {
return user.role === 'admin';
}
8.為NestJS配置tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "ES2021",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": true,
"noImplicitAny": true,
"strictBindCallApply": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"paths": {
"@/*": ["src/*"],
"@modules/*": ["src/modules/*"],
"@common/*": ["src/common/*"]
}
}
}
NestJS 的兩個最重要的選項:
emitDecoratorMetadata:true— 允許 TypeScript 為裝飾器發出元資料(NestJS DI 需要這個)實驗裝飾器:true— 啟用裝飾器
9. 總結
在本文中,您了解了 NestJS 所需的核心 TypeScript 功能:
- 裝飾器:類別、方法、參數裝飾器——NestJS 的基礎
- 介面和類型:定義資料的形狀
- 泛型:建立可重複使用的、型別安全的程式碼
- 列舉:常量的定義
- 實用程式類型:DTO 的部分、選取、省略
- 類型保護裝置:縮小類型是安全的
下一課,我們將安裝 NestJS CLI 並創建我們的第一個專案!