Development Conventions
This document establishes the comprehensive development conventions and professional standards that govern all code contributions to the ts-playground project.
TypeScript Best Practices
Type Safety Standards
- Strict Mode: All TypeScript code must use strict compilation settings (
strict: truein tsconfig) - Explicit Typing: Prefer explicit type annotations for public APIs and complex logic, utilizing type inference judiciously
- Interface Usage: Use
interfacefor object shapes andtypefor complex type operations, unions, and primitives - Generic Typing: Implement generics to ensure type safety across reusable components and functions
- Utility Types: Leverage TypeScript's utility types (
Partial<T>,Pick<T, K>,Omit<T, K>, etc.) for enhanced type manipulation
Naming Conventions
- Functions & Variables: Use
camelCasewith descriptive, action-oriented names (e.g.,calculateTotalAmount,validateUserInput) - Classes & Interfaces: Use
PascalCasefor all class and interface names (e.g.,UserService,DatabaseConnection) - Constants: Use
UPPER_SNAKE_CASEfor constants and environment variables (e.g.,MAX_RETRY_ATTEMPTS,DATABASE_URL) - File Names: Use
kebab-casefor file names (e.g.,user-service.ts,api-routes.ts) - Boolean Variables: Prefix with
is,has,can, orshould(e.g.,isActive,hasPermission,canExecute)
Code Organization & Structure
Directory Structure
- Feature-Based Grouping: Organize code by features rather than technical roles when appropriate
- Index Files: Use
index.tsfiles to provide clear module boundaries and clean imports - Separation of Concerns: Maintain single responsibility principle at both function and module levels
- Type Definitions: Place shared types in dedicated
.types.tsfiles or within atypes/directory
Import Organization
// Standard library imports
import { promises as fs } from 'fs';
import path from 'path';
// Third-party imports
import express from 'express';
import { validate } from 'class-validator';
// Internal imports (relative paths)
import { UserService } from './services/user-service';
import { User, UserCreationRequest } from './types/user.types';
Error Handling Architecture
Custom Error Classes
export class ValidationError extends Error {
constructor(message: string, public field?: string, public value?: unknown) {
super(message);
this.name = 'ValidationError';
}
}
export class DatabaseError extends Error {
constructor(message: string, public operation?: string, public originalError?: Error) {
super(message);
this.name = 'DatabaseError';
}
}
Error Handling Patterns
- Consistent Error Propagation: Either handle errors locally or propagate them to a centralized error handler
- Contextual Error Messages: Include relevant context in error messages for easier debugging
- Error Logging: Implement structured logging for all application errors with appropriate log levels
- Graceful Degradation: Design systems to handle failures gracefully without crashing
Testing Conventions
Test Structure (AAA Pattern)
describe('UserService', () => {
it('should create a new user with valid input', async () => {
// Arrange
const userService = new UserService();
const validUser = { name: 'John Doe', email: 'john@example.com' };
// Act
const result = await userService.createUser(validUser);
// Assert
expect(result).toBeDefined();
expect(result.id).toBeDefined();
expect(result.name).toBe('John Doe');
});
});
Test Organization
- Descriptive Names: Use clear, behavior-describing test names following the pattern
should [expected behavior] when [condition] - Test Coverage: Maintain minimum 80% code coverage for business-critical functionality
- Test Categories: Separate unit tests, integration tests, and end-to-end tests with appropriate file naming
- Mocking Strategy: Use mocks judiciously; prefer real dependencies when testing integration points
Code Documentation Standards
JSDoc Guidelines
/**
* Calculates the total amount for an order, including taxes and discounts.
*
* @param orderItems - Array of items in the order with price and quantity
* @param taxRate - Tax rate to apply to the subtotal (as decimal, e.g., 0.08 for 8%)
* @param discountCode - Optional discount code to apply
* @returns Promise resolving to the calculated total amount
*
* @throws ValidationError if order items are invalid
* @throws CalculationError if tax calculation fails
*
* @example
* const total = await calculateOrderTotal(
* [{ price: 10, quantity: 2 }, { price: 15, quantity: 1 }],
* 0.08,
* 'SAVE10'
* );
* console.log(`Total: $${total.toFixed(2)}`);
*/
export async function calculateOrderTotal(
orderItems: OrderItem[],
taxRate: number,
discountCode?: string
): Promise<number> {
// Implementation
}
Documentation Requirements
- Public APIs: Document all public functions, classes, and interfaces with comprehensive JSDoc
- Complex Logic: Provide inline comments for complex algorithms or non-obvious decisions
- File Headers: Include purpose, author (when appropriate), and last modification date for significant files
- Change Documentation: Update documentation when implementation changes affect public interfaces
Code Quality Standards
Performance Considerations
- Algorithm Efficiency: Choose appropriate data structures and algorithms for optimal performance
- Memory Management: Be mindful of memory usage, especially in long-running processes
- Async Operations: Use async/await appropriately and handle concurrent operations efficiently
- Caching Strategies: Implement appropriate caching for expensive operations
Security Practices
- Input Validation: Validate all external inputs before processing
- SQL Injection Prevention: Use parameterized queries or ORM methods to prevent injection attacks
- Authentication & Authorization: Implement proper access controls for all sensitive operations
- Data Protection: Handle sensitive data appropriately with encryption when necessary