
Adhere to these TypeScript coding best practices and guardrails for high-quality, maintainable, scalable, and robust applications. These guidelines foster a "top senior TypeScript expert Agent" mindset, emphasizing type safety, clarity, and modern standards.
1. Embrace Strict Type Safety:
Eliminate any: Strictly avoid any. Figure out the right typing; if not possible, use unknown, object, or Record<string, unknown>. Cast unknown values only after runtime type checks.
Explicit Typing: Explicitly declare types for function parameters, return values, and complex objects to improve readability and prevent subtle errors.
Leverage Advanced Types: Utilize generics, conditional types, mapped types, discriminated unions, and utility types (e.g., Partial<T>, Required<T>) for robust type safety and reusability.
strictNullChecks: Always enable strictNullChecks in tsconfig.json. Use optional chaining (?.) and nullish coalescing (??).
2. Adhere to ESLint and Code Style:
Respect ESLint Configuration: Strictly follow all rules in eslint.config.ts (or .eslintrc.js), including @typescript-eslint/recommended and @typescript-eslint/recommended-requiring-type-checking.
Automated Formatting: Integrate a code formatter (e.g., Prettier) for consistent style.
Avoid Unused Code: Eliminate unused imports, variables, functions, and classes. ESLint rules should enforce this.
Consistent Naming: Use clear, descriptive, and consistent naming (e.g., PascalCase for types, camelCase for variables/functions).
3. Code Structure and Modularity:
Single Responsibility Principle (SRP): Each file, function, or class should have a single, well-defined responsibility.
Modular Design: Break features into smaller, independent, testable, and reusable modules.
Clear Exports/Imports: Be explicit about exports and imports. Prefer named exports for clarity.
Interface vs. Type Aliases: Prefer interface for object shapes; type for unions, intersections, and primitive aliases.
4. Immutability and Side Effects:
Prefer const and readonly: Use const for unchangeable references; readonly for properties not reassigned after initialization.
Minimize Side Effects: Design pure functions where possible. Make necessary side effects explicit and contained.
5. Error Handling and Robustness:
Graceful Error Handling: Implement robust try...catch blocks for async operations and potential runtime errors.
Custom Error Types: Define custom error classes for specific application errors, providing context for targeted handling.
Type Guards: Use type guards (instanceof, typeof, user-defined) to narrow types in conditional blocks, ensuring safety with polymorphic data.
6. Asynchronous Programming:
Proper Promise Typing: Always type Promises (e.g., Promise<MyDataType>) for correct resolved value typing.
Async/Await: Prefer async/await for cleaner, more readable asynchronous code.
7. Documentation and Readability:
JSDoc for Public APIs: Document public functions, classes, and interfaces with JSDoc for clear descriptions and IDE support.
Meaningful Comments: Use comments sparingly, focusing on why something is done.
Code Simplicity: Strive for the simplest possible solution; avoid over-engineering.
8. Performance Considerations (Type System):
Avoid Excessive Type Complexity: Overly complex or deeply nested types can impact TypeScript compilation. Prioritize clarity and maintainability.
Type Inference Optimization: Be aware that large union types or deeply nested conditional types can slow type inference.
9. Testing:
Unit and Integration Tests: Write comprehensive tests. Compile-time type safety doesn't replace runtime validation.
Test-Driven Development (TDD): Consider TDD to drive design and ensure testability.
10. Dependency Management and External Libraries:
Type Definitions: Ensure all third-party libraries have proper type definitions (@types/library-name). Create local .d.ts files if needed.
Version Control: Pin dependencies to specific versions to avoid unexpected breaking changes.
Consistently applying these principles leads to robust, type-safe TypeScript code and cultivates a disciplined, senior-level software architect approach.