1. NestJS にとって TypeScript が重要なのはなぜですか?
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 の 2 つの最も重要なオプション:
EmitDecoratorMetadata: true— TypeScript がデコレーターのメタデータを出力できるようにします (NestJS DI が必要です)実験的デコレータ: true— デコレータを有効にする
9. まとめ
この記事では、NestJS に必要な核となる TypeScript 機能を学習しました。
- デコレーター: クラス、メソッド、パラメータのデコレータ — NestJS の基礎
- インターフェースとタイプ: データの形状を定義します
- ジェネリック: 再利用可能でタイプセーフなコードを作成する
- 列挙型: 定数の定義
- ユーティリティの種類: DTO の場合は部分、選択、省略
- タイプガード:絞り込みタイプが安全
次のレッスンでは、NestJS CLI をインストールし、最初のプロジェクトを作成します。