Skip to main content

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: true in tsconfig)
  • Explicit Typing: Prefer explicit type annotations for public APIs and complex logic, utilizing type inference judiciously
  • Interface Usage: Use interface for object shapes and type for 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 camelCase with descriptive, action-oriented names (e.g., calculateTotalAmount, validateUserInput)
  • Classes & Interfaces: Use PascalCase for all class and interface names (e.g., UserService, DatabaseConnection)
  • Constants: Use UPPER_SNAKE_CASE for constants and environment variables (e.g., MAX_RETRY_ATTEMPTS, DATABASE_URL)
  • File Names: Use kebab-case for file names (e.g., user-service.ts, api-routes.ts)
  • Boolean Variables: Prefix with is, has, can, or should (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.ts files 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.ts files or within a types/ 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