Bỏ qua để đến nội dung
Knowledge Hub

Sáu quy tắc đặt tên và cách áp vào TypeScript, NestJS Cơ bản

Thời gian đọc ước tính: 6 phút

Trang này trả lời: quy tắc chung nào áp cho mọi cái tên, và áp vào code TypeScript, NestJS cụ thể ra sao.

Đang tải diagram…

Người đọc cần biết giá trị này là gì, dùng để làm gì, không phải nó được tính ra sao.

// Trước
const d = 30;
const list2 = orders.filter((o) => o.s === 3);
// Sau
const refundWindowDays = 30;
const shippedOrders = orders.filter((order) => order.status === OrderStatus.SHIPPED);

Tên một chữ cái chỉ chấp nhận cho biến sống rất ngắn (Google TS Style Guide: phạm vi từ 10 dòng trở xuống), như i trong vòng lặp.

Codebase có cả getUser, fetchUser, loadUser, retrieveUser thì người đọc sẽ đoán chúng khác nhau. Chọn nghĩa cho từng động từ và giữ ở mọi module:

Động từ Nghĩa trong team Khi không có kết quả
find... Truy vấn, có thể không thấy Trả null / mảng rỗng
get... Bắt buộc phải có Ném lỗi (NotFoundException)
fetch... Gọi qua mạng (HTTP, service khác) Tuỳ, nhưng luôn có timeout
list... Trả danh sách có phân trang Mảng rỗng
create / update / delete Ghi Dùng thống nhất, không trộn add / remove / insert

Bảng này là một lựa chọn, không phải chuẩn. Giá trị nằm ở chỗ cả team dùng cùng một bảng.

data, info, item, obj, manager, helper, utils, handle, process đúng với mọi thứ, nên không nói gì. Chúng còn là nam châm hút code: utils.ts sau hai năm thành bãi rác 3.000 dòng.

// Trước
class OrderManager { handle(data: any) { /* ... */ } }
// utils.ts: formatMoney, retry, parseJwt, slugify...
// Sau
class OrderCancellationService { cancel(command: CancelOrderCommand) { /* ... */ } }
// money-format.ts, retry-with-backoff.ts, jwt-claims.ts

Mẹo review: không đặt được tên cụ thể cho class thì nó thường đang làm hai việc. Tách ra trước, tên sẽ tự hiện.

4. Boolean là câu hỏi có/không, không phủ định

Phần tiêu đề “4. Boolean là câu hỏi có/không, không phủ định”

Dùng tiền tố is, has, can, should để đọc lên như câu hỏi. Tránh tên phủ định: !isNotActive buộc não đảo hai lần.

// Trước
if (!user.notVerified && !disableRetry) { ... }
// Sau
if (user.isVerified && shouldRetry) { ... }

Với field của API có quan điểm ngược lại: Google AIP-140 khuyên bỏ is (disabled thay vì is_disabled). Chọn một quy tắc cho JSON contract và giữ nó.

timeout = 30 là 30 giây hay 30 mili giây? Giá trị trông hợp lý ở cả hai cách hiểu, nên sự cố rất khó tìm.

// Trước
const timeout = 30;
const maxSize = 10;
// Sau
const timeoutMs = 30_000;
const maxUploadSizeBytes = 10 * 1024 * 1024;

Khi có thể, đẩy đơn vị vào kiểu (ví dụ type Duration). Còn là number thì đơn vị phải ở trong tên: Ms, Seconds, Bytes, Cents. AIP-140 cũng khuyên viết tắt đơn vị quen thuộc trong field name, như distance_km.

6. Không tiền tố kiểu, không viết tắt tự chế

Phần tiêu đề “6. Không tiền tố kiểu, không viết tắt tự chế”

Kiểu đã có trong TypeScript, đừng lặp lại trong tên. Google TS Style Guide cấm Hungarian notation và cấm viết tắt bằng cách bỏ chữ giữa từ (ví dụ cstmrId).

Tránh Dùng Lý do
strName, arrOrders, bIsPaid name, orders, isPaid Kiểu đã có trong type
IOrderRepository OrderRepository Style guide không đánh dấu interface
_balance cho private private balance Dùng modifier, không dùng _
cstmr, qty, amt, usrCfg customer, quantity, amount, userConfig Viết tắt tự chế làm grep thất bại
loadHTTPURL, userID loadHttpUrl, userId Viết tắt coi như một từ

Viết tắt được chấp nhận khi ai cũng biết: id, url, http, db, config, api.

Google TypeScript Style Guide là chuẩn công khai, đầy đủ và có lý do cho từng điều. Những điểm hay gặp trong review:

  • UpperCamelCase cho class, interface, type, enum, decorator, type parameter.
  • lowerCamelCase cho biến, tham số, hàm, method, property.
  • CONSTANT_CASE chỉ cho hằng số cấp module, static field cấp module và giá trị enum. const trong hàm vẫn là lowerCamelCase.
  • Không I prefix cho interface, không _ prefix/suffix cho private.
  • Viết tắt coi như một từ: loadHttpUrl, không phải loadHTTPURL.
// Trước
const Max_Retry = 3;
interface IPaymentGateway { ChargeCard(amt: number): Promise<any>; }
class paymentService { private _gw: IPaymentGateway; }
// Sau
const MAX_RETRY_ATTEMPTS = 3;
interface PaymentGateway { chargeCard(amountCents: number): Promise<ChargeResult>; }
class PaymentService { constructor(private readonly gateway: PaymentGateway) {} }

Đưa phần lớn quy tắc này vào ESLint (@typescript-eslint/naming-convention) để máy kiểm; review chỉ bàn về nghĩa.

Docs NestJS dùng một mẫu nhất quán trong mọi ví dụ (dù không phát biểu thành luật): file kebab-case có hậu tố theo loại, class UpperCamelCase có hậu tố tương ứng. CLI nest g resource orders cũng sinh theo mẫu này.

Loại File Class
Module orders.module.ts OrdersModule
Controller orders.controller.ts OrdersController
Service orders.service.ts OrdersService
DTO tạo mới dto/create-order.dto.ts CreateOrderDto
DTO cập nhật dto/update-order.dto.ts UpdateOrderDto (thường PartialType(CreateOrderDto))
Entity entities/order.entity.ts Order
Guard, pipe, decorator roles.guard.ts, tenant-id.decorator.ts RolesGuard, TenantId

DTO đặt theo hành động: CreateOrderDto, CancelOrderDto, không phải OrderDto dùng chung. DTO dùng chung sẽ dần có field tuỳ chọn cho từng use case, và validation mất ý nghĩa. Xem modules, providers, controllers.

Before → after: những cái tên gặp trong review

Phần tiêu đề “Before → after: những cái tên gặp trong review”
Trước Vấn đề Sau
processData(data) Hai từ rỗng nghĩa reconcileSettlementReport(report)
flag Không biết bật nghĩa là gì shouldNotifyCustomer
isNotDeleted Phủ định kép khi ! isActive (hoặc deletedAt IS NULL)
timeout: 5 Thiếu đơn vị timeoutMs: 5_000
getUser() trả null Sai nghĩa get của team findUserById()
UserManager “Manager” của mọi thứ UserRegistrationService, UserProfileService
IOrderRepo Tiền tố I, viết tắt OrderRepository

Tên ở database, API và event có bảng riêng ở các trang sau.

Tiếp theo: PostgreSQL.