TypeScript Standards
TypeScript Standards
Section titled “TypeScript Standards”1. Package Management
Section titled “1. Package Management”- Tool:
pnpmpreferred,npmacceptable. Lock files committed. - Version: TypeScript 5.0+. Use strict mode.
- Config:
tsconfig.jsonwith strict compiler options.
2. Code Style
Section titled “2. Code Style”- Formatter:
prettierwith line length 120. Run viamake fmt. - Linter:
eslintwith TypeScript plugin. Use@typescript-eslintrules. - Type Checker:
tsc --noEmitin CI. Noanywithout explicit justification.
tsconfig.json
Section titled “tsconfig.json”{ "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }}3. Naming Conventions
Section titled “3. Naming Conventions”- Files:
kebab-case.tsorkebab-case.tsx - Classes/Interfaces/Types:
PascalCase - Variables/Functions:
camelCase - Constants:
UPPER_SNAKE_CASEorcamelCasewithconst - Private:
_leadingUnderscore(convention only, not enforced)
4. Project Structure
Section titled “4. Project Structure”src/├── domain/│ ├── entities/│ └── value-objects/├── application/│ ├── use-cases/│ └── interfaces/└── infrastructure/ └── repositories/5. Type System
Section titled “5. Type System”- Strict Mode: Always enabled. No
any,unknownpreferred overany. - Type Inference: Let TypeScript infer types when obvious. Explicit types for public APIs.
- Generics: Use generics for reusable code. Use constraints with
extends. - Utility Types: Leverage
Partial<T>,Pick<T>,Omit<T>,Record<K, V>.
Example
Section titled “Example”interface Repository<T> { findById(id: string): Promise<T | null>; save(entity: T): Promise<void>;}
type Result<T> = | { success: true; data: T } | { success: false; error: Error };
class Email { private constructor(private readonly value: string) {}
static create(value: string): Email { if (!/^[^@]+@[^@]+\.[^@]+$/.test(value)) { throw new InvalidEmailError(value); } return new Email(value); }
toString(): string { return this.value; }}6. Error Handling
Section titled “6. Error Handling”- Custom Errors: Extend
Errorclass. Use typed error classes. - Result Pattern: Use
Result<T>type for functional error handling. - Async Errors: Use
Promise<T>with proper error handling.
class DomainError extends Error { constructor(message: string, public readonly cause?: Error) { super(message); this.name = this.constructor.name; Error.captureStackTrace(this, this.constructor); }}
class InvalidEmailError extends DomainError { constructor(public readonly email: string) { super(`Invalid email: ${email}`); }}7. Testing
Section titled “7. Testing”- Framework:
vitestorjest. Use@testing-libraryfor component tests. - Mocking:
vitestbuilt-in mocking orjest.mock(). Mock external dependencies. - Coverage: 95% is the absolute minimum for any module. Target 100% for domain, 95%+ for application and infrastructure.
Test Structure
Section titled “Test Structure”import { describe, it, expect, vi } from 'vitest';import { UserService } from './user-service';import { Email } from './domain/email';
describe('UserService', () => { it('should create user with valid email', () => { // Given const email = Email.create('test@example.com');
// When const user = UserService.createUser(email, 'Test User');
// Then expect(user.email.toString()).toBe('test@example.com'); });});8. Async/Await
Section titled “8. Async/Await”- Promises: Use
async/awaitover.then(). UsePromise.all()for parallel operations. - Error Handling: Always handle promise rejections. Use
try-catchwith async functions.
async function fetchUser(id: string): Promise<User> { try { const user = await userRepository.findById(id); if (!user) { throw new UserNotFoundException(id); } return user; } catch (error) { if (error instanceof DomainError) { throw error; } throw new UserFetchError(`Failed to fetch user: ${id}`, error); }}9. Dependencies
Section titled “9. Dependencies”Common Libraries
Section titled “Common Libraries”- HTTP:
axiosorfetch(native) - Validation:
zodfor runtime validation and type inference - State Management:
zustand,redux-toolkit, or framework-specific - Logging:
pinoorwinston
10. Documentation
Section titled “10. Documentation”- JSDoc: Use JSDoc comments for public APIs. Generate docs with
typedoc. - Format: Use
@param,@returns,@throwstags.
/** * Creates a new user with validated email address. * * @param email - Valid email address (must match RFC 5322) * @param name - User's full name (non-null, non-empty) * @returns New User entity instance * @throws {InvalidEmailError} If email format is invalid * @example * ```ts * const user = createUser(Email.create('test@example.com'), 'John Doe'); * ``` */function createUser(email: Email, name: string): User { // Implementation}11. Module System
Section titled “11. Module System”- ES Modules: Use
import/export. Avoidrequire(). - Barrel Exports: Use
index.tsfor public API. Re-export selectively. - Path Aliases: Configure path aliases in
tsconfig.jsonfor clean imports.
12. Framework-Specific
Section titled “12. Framework-Specific”- React: Use functional components with hooks. Prefer
useState,useEffect,useCallback. - Node.js: Use ES modules. Leverage
async/awaitfor I/O operations. - Build Tools: Use
vite,esbuild, ortsupfor bundling.