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.
### **TypeScript Coding Best Practices and Guardrails**
**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.