Six naming rules and how to apply them in TypeScript and NestJS Basic
Estimated reading time: 6 min read
This page answers: which general rules apply to every name, and how to apply them concretely in TypeScript and NestJS code.
Loading diagram…
Six core rules
Section titled “Six core rules”1. Names state intent, not mechanics
Section titled “1. Names state intent, not mechanics”The reader needs to know what this value is and what it is for, not how it was computed.
// Beforeconst d = 30;const list2 = orders.filter((o) => o.s === 3);
// Afterconst refundWindowDays = 30;const shippedOrders = orders.filter((order) => order.status === OrderStatus.SHIPPED);Single-letter names are only acceptable for very short-lived variables (Google TS Style Guide: a scope of 10 lines or fewer), like i in a loop.
2. One word per concept
Section titled “2. One word per concept”If a codebase has getUser, fetchUser, loadUser and retrieveUser, readers will assume they differ. Give each verb a meaning and keep it across every module:
| Verb | Meaning in the team | When there is no result |
|---|---|---|
find... |
Query, may find nothing | Return null / empty array |
get... |
Must exist | Throw (NotFoundException) |
fetch... |
Network call (HTTP, another service) | Depends, but always with a timeout |
list... |
Returns a paginated list | Empty array |
create / update / delete |
Writes | Use consistently, do not mix with add / remove / insert |
This table is one choice, not a standard. Its value lies in the whole team using the same table.
3. Ban empty words
Section titled “3. Ban empty words”data, info, item, obj, manager, helper, utils, handle, process fit anything, so they say nothing. They are also code magnets: after two years utils.ts becomes a 3,000-line dumping ground.
// Beforeclass OrderManager { handle(data: any) { /* ... */ } }// utils.ts: formatMoney, retry, parseJwt, slugify...
// Afterclass OrderCancellationService { cancel(command: CancelOrderCommand) { /* ... */ } }// money-format.ts, retry-with-backoff.ts, jwt-claims.tsReview tip: if you cannot give a class a specific name, it is usually doing two things. Split it first and the names will appear.
4. Booleans are yes/no questions, not negations
Section titled “4. Booleans are yes/no questions, not negations”Use the prefixes is, has, can, should so they read like questions. Avoid negated names: !isNotActive forces the brain to flip twice.
// Beforeif (!user.notVerified && !disableRetry) { ... }
// Afterif (user.isVerified && shouldRetry) { ... }For API fields there is the opposite view: Google AIP-140 recommends dropping is (disabled rather than is_disabled). Pick one rule for the JSON contract and stick to it.
5. Units belong in the name
Section titled “5. Units belong in the name”Is timeout = 30 30 seconds or 30 milliseconds? The value looks plausible either way, so the resulting incident is very hard to find.
// Beforeconst timeout = 30;const maxSize = 10;
// Afterconst timeoutMs = 30_000;const maxUploadSizeBytes = 10 * 1024 * 1024;When possible, push the unit into the type (e.g. a Duration type). As long as it is a number, the unit must be in the name: Ms, Seconds, Bytes, Cents. AIP-140 also recommends familiar unit abbreviations in field names, such as distance_km.
6. No type prefixes, no home-made abbreviations
Section titled “6. No type prefixes, no home-made abbreviations”TypeScript already has the type; do not repeat it in the name. The Google TS Style Guide forbids Hungarian notation and abbreviations made by dropping letters inside a word (e.g. cstmrId).
| Avoid | Use | Reason |
|---|---|---|
strName, arrOrders, bIsPaid |
name, orders, isPaid |
The type already says it |
IOrderRepository |
OrderRepository |
The style guide does not mark interfaces |
_balance for private |
private balance |
Use the modifier, not _ |
cstmr, qty, amt, usrCfg |
customer, quantity, amount, userConfig |
Home-made abbreviations make grep fail |
loadHTTPURL, userID |
loadHttpUrl, userId |
Treat abbreviations as words |
Abbreviations everyone knows are fine: id, url, http, db, config, api.
TypeScript: follow the Google TS Style Guide
Section titled “TypeScript: follow the Google TS Style Guide”The Google TypeScript Style Guide is a public, complete standard with a reason for each rule. The points that come up most in review:
UpperCamelCasefor classes, interfaces, types, enums, decorators, type parameters.lowerCamelCasefor variables, parameters, functions, methods, properties.CONSTANT_CASEonly for module-level constants, module-level static fields and enum values. Aconstinside a function is stilllowerCamelCase.- No
Iprefix for interfaces, no_prefix/suffix for private members. - Abbreviations are treated as words:
loadHttpUrl, notloadHTTPURL.
// Beforeconst Max_Retry = 3;interface IPaymentGateway { ChargeCard(amt: number): Promise<any>; }class paymentService { private _gw: IPaymentGateway; }
// Afterconst MAX_RETRY_ATTEMPTS = 3;interface PaymentGateway { chargeCard(amountCents: number): Promise<ChargeResult>; }class PaymentService { constructor(private readonly gateway: PaymentGateway) {} }Put most of these rules into ESLint (@typescript-eslint/naming-convention) so the machine checks them; review only discusses meaning.
NestJS: files and classes
Section titled “NestJS: files and classes”The NestJS docs use one consistent pattern across all examples (though it is not stated as a rule): kebab-case files with a suffix per kind, UpperCamelCase classes with the matching suffix. The CLI nest g resource orders generates the same pattern.
| Kind | File | Class |
|---|---|---|
| Module | orders.module.ts |
OrdersModule |
| Controller | orders.controller.ts |
OrdersController |
| Service | orders.service.ts |
OrdersService |
| Create DTO | dto/create-order.dto.ts |
CreateOrderDto |
| Update DTO | dto/update-order.dto.ts |
UpdateOrderDto (usually PartialType(CreateOrderDto)) |
| Entity | entities/order.entity.ts |
Order |
| Guard, pipe, decorator | roles.guard.ts, tenant-id.decorator.ts |
RolesGuard, TenantId |
Name DTOs after the action: CreateOrderDto, CancelOrderDto, not a shared OrderDto. A shared DTO gradually gains optional fields for each use case, and validation loses its meaning. See modules, providers, controllers.
Before → after: names seen in review
Section titled “Before → after: names seen in review”| Before | Problem | After |
|---|---|---|
processData(data) |
Two empty words | reconcileSettlementReport(report) |
flag |
Unclear what “on” means | shouldNotifyCustomer |
isNotDeleted |
Double negation with ! |
isActive (or deletedAt IS NULL) |
timeout: 5 |
Missing unit | timeoutMs: 5_000 |
getUser() returns null |
Violates the team’s meaning of get |
findUserById() |
UserManager |
“Manager” of everything | UserRegistrationService, UserProfileService |
IOrderRepo |
I prefix, abbreviation |
OrderRepository |
Names in the database, APIs and events have their own tables on the following pages.
Next: PostgreSQL.