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.