Detailed reference for TypeScript naming conventions and project structure
Consistent naming and structure eliminate ambiguity, reduce cognitive load when navigating the codebase, and make code self-documenting. These conventions follow the Google TypeScript Style Guide and the TypeScript Handbook.
| Construct | Convention | Example |
|---|---|---|
| Variables, functions, methods | camelCase | getUserById, remainingRetries |
| Classes, interfaces, type aliases, enums | PascalCase | UserService, ApiResponse |
| Constants (compile-time / env-level) | UPPER_SNAKE_CASE | , |
MAX_RETRIESAPI_BASE_URL| Config objects, module-level non-primitive constants | camelCase | defaultConfig, routeMap |
| Generic type parameters | Single uppercase or T-prefix | T, K, V, TResponse, TInput |
| Boolean variables and properties | is, has, should, can prefix | isActive, hasPermission, canEdit |
| Private class members | no underscore prefix | private count (not private _count) |
I prefix on interfaces: User, not IUserT prefix on type aliases (except generics): ApiResponse, not TApiResponseUserRepository, CacheOptionsHttpMethod, Result<T, E>user-service.ts, api-client.ts.ts for pure TypeScript, .tsx only for files containing JSX*.test.ts or *.spec.ts (be consistent within the project)index.ts) only at package/module boundaries — not in every directorysrc/
auth/
auth.service.ts
auth.controller.ts
auth.types.ts
auth.test.ts
orders/
orders.service.ts
orders.repository.ts
orders.types.ts
orders.test.ts
shared/
errors.ts
logger.ts
types.ts
src/
controllers/
auth.controller.ts
orders.controller.ts
services/
auth.service.ts
orders.service.ts
# Problem: adding a feature requires touching many directories
# Problem: related code is scattered, increasing coupling between modules
import type { ... })// Simple: single uppercase letter
function identity<T>(value: T): T { return value; }
function mapEntries<K, V>(map: Map<K, V>): [K, V][] { /* ... */ }
// Complex: descriptive T-prefixed name
function transform<TInput, TOutput>(
input: TInput,
fn: (val: TInput) => TOutput,
): TOutput {
return fn(input);
}
// BAD: meaningless multi-letter names that aren't T-prefixed
function transform<A, B>(input: A, fn: (val: A) => B): B {
return fn(input);
}