Enhanced TypeScript & NestJS Development
Comprehensive guidelines for building robust, maintainable TypeScript applications with NestJS. These standards promote consistency, readability, and long-term sustainability across complex enterprise applications.
Instructions
When writing TypeScript and NestJS code, follow these comprehensive guidelines:
TypeScript Core Principles
**Fundamental Standards:**
Use precise, meaningful English for all code and documentationEmploy strong typing throughout: - Explicitly declare types for all variables, parameters, and return values
- Avoid `any` type; prefer `unknown` when type is undetermined
- Create domain-specific types and interfaces
- Leverage discriminated unions and generics for complex scenarios
Document public APIs with JSDoc including descriptions, parameters, return values, examples, and exceptionsMaintain clean code structure: eliminate unnecessary blank lines, one primary export per file, focused single responsibilityUse TypeScript latest features: optional chaining (`?.`), nullish coalescing (`??`), template literal types**Naming Conventions:**
`PascalCase` for classes, interfaces, types, enums, decorators`camelCase` for variables, functions, methods, properties`kebab-case` for file and directory names`UPPER_SNAKE_CASE` for constants and environment variablesPrefix booleans with verbs: `isEnabled`, `hasPermission`, `canModify`Use complete, correctly spelled words; acceptable abbreviations: API, URL, JWT, UUID, loop counters (`i`, `j`), `err`/`error`, `ctx`/`context`, `req`/`res`/`next`**Function Design:**
Single responsibility with maximum 20 logical operationsSemantic naming: action verbs + object (`calculateTotal`), predicates (`isValid`), event handlers (`onSubmit`)Early returns for preconditions, limit nesting to 2-3 levelsUse destructured objects for >2 parameters (Receive-object, Return-object pattern)Provide meaningful default values and parameter validation**Data Management:**
Use rich domain models over primitivesEmploy value objects for concepts with intrinsic rules (Email, Currency, PhoneNumber)Validate at domain boundaries with class-validator for DTOsPrioritize immutability: `readonly`, `as const`, proper copy mechanismsDistinguish commands from queries with clear data transformation patterns**Class Architecture:**
Follow SOLID principles: - **S**ingle Responsibility: one reason to change
- **O**pen/Closed: open for extension, closed for modification
- **L**iskov Substitution: subtypes substitutable for base types
- **I**nterface Segregation: client-specific interfaces
- **D**ependency Inversion: depend on abstractions
Favor composition over inheritanceMaximum ~200 logical operations, ≤10 public methods, ≤10 properties per classDefine clear contracts with interfaces and abstract classes**Error Handling:**
Create hierarchy of application-specific exceptionsInclude context information in exception messagesCatch to add context or handle recoverable errors; propagate unrecoverable onesTransform technical exceptions to domain-specific at boundariesImplement retry mechanisms, circuit breakers, and fallback strategies**Testing Strategy:**
Comprehensive coverage: unit, integration, end-to-end, performance testsFollow AAA (Arrange-Act-Assert) pattern or Given-When-Then structureDescriptive test names: `should_returnFilteredResults_whenGivenValidParams`Use appropriate test doubles: mocks, stubs, fakes, spiesNestJS Architecture
**Modular Design:**
Organize by business capability or bounded contextMaintain clear module boundaries with explicit public APIsStructure: one primary module class, feature controllers, domain services, data modelsExport only necessary components; use feature and shared modules**API Design:**
Create RESTful APIs: resource-oriented endpoints, appropriate HTTP methods, meaningful status codesEnforce strict validation with DTOs using class-validatorImplement standardized response structures with consistent success/error formatsPlan for versioning, backward compatibility, and deprecation**Data Persistence:**
Use repository pattern and unit of work for transaction managementLeverage MikroORM: clean entity models, migrations, indexing, optimistic lockingDesign for performance: efficient querying, eager/lazy loading, caching, paginationEnsure data integrity: transactions, database constraints, eventual consistency, audit logging**Service Implementation:**
One service per primary entity or use caseSeparate command and query services; application services for orchestrationUse constructor injection for required dependenciesCreate stateless services when possible; use decorators for cross-cutting concerns**Core Infrastructure:**
Implement global exception filters, logging middleware, auth guards, monitoring interceptorsStructured logging with correlation IDs, metrics collection, distributed tracing, health checksSecurity: input validation, output encoding, rate limiting, CSRF protection**Advanced Testing:**
Unit tests with isolated dependencies, integration with test databases, E2E with running servicesUse NestJS testing module, test fixtures, factory functionsContract tests, chaos testing, security testing, mutation testingAutomate in CI: coverage reporting, visual regression testingDevelopment Workflow
**Code Organization:**
Feature-oriented folders with clear API/domain/infrastructure separationStandardized file naming and logical component groupingRegular dependency updates with pinning for stability**Quality Assurance:**
ESLint with custom rules, Prettier, Husky pre-commit hooksCode reviews focusing on design and maintainabilityAutomated checks before human review**Documentation:**
OpenAPI/Swagger for API docsTechnical architecture documentation and inline code comments for complex logicDecision records for significant choicesGenerate from code where possible; maintain under version controlExamples
**Function with proper typing and validation:**
```typescript
interface UserSearchParams {
query: string;
limit?: number;
offset?: number;
}
/**
* Searches users based on query parameters
* @param params - Search parameters with query string and pagination
* @returns Paginated list of matching users
* @throws {ValidationError} when query is empty
* @example
* const results = await searchUsers({ query: 'john', limit: 10 });
*/
async function searchUsers(params: UserSearchParams): Promise<PaginatedResult<User>> {
const { query, limit = 20, offset = 0 } = params;
if (!query.trim()) {
throw new ValidationError('Search query cannot be empty');
}
return await userRepository.search({ query, limit, offset });
}
```
**NestJS service with proper dependency injection:**
```typescript
@Injectable()
export class OrderService {
constructor(
private readonly orderRepository: OrderRepository,
private readonly paymentService: PaymentService,
private readonly logger: Logger,
) {}
async createOrder(dto: CreateOrderDto): Promise<Order> {
this.logger.log(`Creating order for user ${dto.userId}`);
const order = await this.orderRepository.create(dto);
await this.paymentService.processPayment(order);
return order;
}
}
```
**Testing with NestJS:**
```typescript
describe('OrderService', () => {
let service: OrderService;
let mockRepository: jest.Mocked<OrderRepository>;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
OrderService,
{
provide: OrderRepository,
useFactory: () => ({
create: jest.fn(),
}),
},
],
}).compile();
service = module.get(OrderService);
mockRepository = module.get(OrderRepository);
});
it('should_createOrder_whenGivenValidDto', async () => {
// Arrange
const dto = { userId: '123', items: [] };
const expectedOrder = { id: '1', ...dto };
mockRepository.create.mockResolvedValue(expectedOrder);
// Act
const result = await service.createOrder(dto);
// Assert
expect(result).toEqual(expectedOrder);
expect(mockRepository.create).toHaveBeenCalledWith(dto);
});
});
```
Constraints
Never use `any` type unless absolutely necessaryMaximum 20 logical operations per functionMaximum ~200 logical operations per classLimit nesting depth to 2-3 levelsOne primary export per fileAlways validate external data at system boundariesUse constructor injection for required dependencies in NestJSFollow SOLID principles for all class design