Elite TypeScript Development
Expert guidance for building production-grade TypeScript applications with functional programming principles, multi-provider LLM architectures, and delightful developer APIs.
Overview
This skill provides expertise in:
Multi-provider LLM architecturesFunctional programming in TypeScriptType-safe API designComposable, immutable solutionsModern TypeScript ecosystem best practicesInstructions
1. Architecture & Design Philosophy
When designing code:
**Favor functions over classes** - Use functional programming patterns unless OOP provides clear benefits**Favor types over interfaces** - Use `type` for most declarations; reserve `interface` for extensibility needs**Prioritize composability** - Build small, reusable functions that combine elegantly**Ensure immutability** - Avoid mutations; use pure functions that return new values**Choose pragmatic simplicity** - Solve the current problem elegantly without over-engineering2. Naming Conventions
Apply these naming rules consistently:
**Files**: `kebab-case` (e.g., `user-service.ts`, `llm-provider.ts`)**Variables & Functions**: `camelCase` (e.g., `userData`, `fetchUser()`)**Classes, Types, Interfaces**: `UpperCamelCase` (e.g., `UserService`, `RequestConfig`)**Constants & Enums**: `ALL_CAPS` (e.g., `MAX_RETRIES`, `StatusCode.OK`)3. File Organization
Structure projects for clarity:
```
src/
├── core/ # Business logic
├── providers/ # LLM and external service integrations
├── utils/ # Pure utility functions
├── types/ # Shared type definitions
├── components/ # UI components (if applicable)
└── index.ts # Main exports
```
Group related functionality into modulesUse `index.ts` files to simplify importsSeparate concerns: logic, UI, and utilities in different directories4. TypeScript Best Practices
#### Variable Declarations
Use `const` by default; only use `let` when reassignment is necessaryNever use `var`#### Functions
Prefer arrow functions for lexical scoping and concisenessWrite pure functions when possible (no side effects)Example: ```typescript
const add = (a: number, b: number): number => a + b;
```
#### Type System
Enable TypeScript strict modeUse generics for reusable type-safe functionsLeverage type aliases and utility types (`Partial`, `Pick`, `Omit`, etc.)Implement discriminated unions for complex state management#### Error Handling
Create custom error types that extend `Error`Use `try-catch` with async/awaitValidate input with Zod schemas at runtime#### Async Operations
Use `async/await` instead of callbacks or raw promisesHandle errors properly with try-catch blocksConsider Promise.all for parallel operations5. Code Quality Standards
Apply these principles:
**Single Responsibility**: Each function/class does one thing well**Dependency Injection**: Pass dependencies as parameters for testability**Comprehensive Testing**: Write unit tests for all business logic**Proper Logging**: Log errors and important events with context**Type Safety**: Leverage TypeScript's type system fully6. Library Usage
Use these libraries according to best practices:
**axios (^1.7.5)**: Implement interceptors for global error handling and auth**js-yaml (^4.1.0)**: Use type-safe schemas for parsing YAML**mime-types (^2.1.35)**: Detect MIME types and map file extensions**node-gyp (^10.2.0)**: Configure properly in build pipeline for native addons**uuid (^10.0.0)**: Use `v4()` for random unique identifiers**zod (^3.23.8)**: Create reusable validation schemas for runtime type checkingExample with Zod:
```typescript
import { z } from 'zod';
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
age: z.number().int().positive(),
});
type User = z.infer<typeof UserSchema>;
const validateUser = (data: unknown): User => UserSchema.parse(data);
```
7. Documentation Standards
Document your code thoroughly:
Use **JSDoc comments** for all public functions, classes, and complex typesInclude `@param`, `@returns`, and `@throws` tagsAdd usage examples in JSDoc where helpfulKeep README.md updated with: - Setup instructions
- Usage examples
- API documentation
- Contribution guidelines
Example:
```typescript
/**
* Fetches user data from the API
* @param userId - The unique identifier for the user
* @returns Promise resolving to user data
* @throws {ApiError} When the API request fails
* @example
* const user = await fetchUser('123e4567-e89b-12d3-a456-426614174000');
*/
const fetchUser = async (userId: string): Promise<User> => {
// implementation
};
```
8. Multi-Provider LLM Architecture
When implementing LLM providers:
Create a common interface for all providersUse dependency injection to swap providersImplement proper error handling and retry logicType all provider responses with Zod schemasSupport streaming and non-streaming modesHandle rate limits and quotas gracefullyExamples
Functional Composition
```typescript
type Transform<T> = (input: T) => T;
const compose = <T>(...fns: Transform<T>[]): Transform<T> =>
(input: T) => fns.reduceRight((acc, fn) => fn(acc), input);
const trim = (s: string): string => s.trim();
const lowercase = (s: string): string => s.toLowerCase();
const normalize = compose(lowercase, trim);
```
Type-Safe Configuration
```typescript
import { z } from 'zod';
const ConfigSchema = z.object({
apiKey: z.string().min(1),
timeout: z.number().positive().default(5000),
retries: z.number().int().nonnegative().default(3),
});
type Config = z.infer<typeof ConfigSchema>;
const loadConfig = (raw: unknown): Config => ConfigSchema.parse(raw);
```
Constraints
Always enable TypeScript strict modeNever use `any` type without explicit justificationAll public APIs must have comprehensive JSDoc commentsBusiness logic must have unit test coverageFollow the established naming conventions without exceptionPrefer immutability and pure functions