typescript-node-expert
Expert TypeScript/Node.js developer for building high-quality, performant, and maintainable CLI tools and libraries. Enforces best practices, strict typing, and modern patterns.
Best use case
typescript-node-expert is best used when you need a repeatable AI agent workflow instead of a one-off prompt. It is especially useful for teams working in multi. Expert TypeScript/Node.js developer for building high-quality, performant, and maintainable CLI tools and libraries. Enforces best practices, strict typing, and modern patterns.
Expert TypeScript/Node.js developer for building high-quality, performant, and maintainable CLI tools and libraries. Enforces best practices, strict typing, and modern patterns.
Users should expect a more consistent workflow output, faster repeated execution, and less time spent rewriting prompts from scratch.
Practical example
Example input
Use the "typescript-node-expert" skill to help with this workflow task. Context: Expert TypeScript/Node.js developer for building high-quality, performant, and maintainable CLI tools and libraries. Enforces best practices, strict typing, and modern patterns.
Example output
A structured workflow result with clearer steps, more consistent formatting, and an output that is easier to reuse in the next run.
When to use this skill
- Use this skill when you want a reusable workflow rather than writing the same prompt again and again.
When not to use this skill
- Do not use this when you only need a one-off answer and do not need a reusable workflow.
- Do not use it if you cannot install or maintain the related files, repository context, or supporting tools.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/typescript-node-expert/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How typescript-node-expert Compares
| Feature / Agent | typescript-node-expert | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Expert TypeScript/Node.js developer for building high-quality, performant, and maintainable CLI tools and libraries. Enforces best practices, strict typing, and modern patterns.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
Related Guides
SKILL.md Source
# TypeScript/Node.js Expert
## Overview
This skill provides expert guidance for TypeScript and Node.js development with a focus on:
- **Type Safety**: Strict TypeScript with full type coverage
- **Performance**: Async patterns, streaming, memory efficiency
- **Maintainability**: Clean architecture, SOLID principles
- **Modern Standards**: ES2022+, ESM modules, latest Node.js features
## PROACTIVE USAGE
**Invoke this skill before ANY TypeScript/Node.js work:**
- New features or modules
- Refactoring existing code
- Performance optimization
- Code review
- Bug fixes in TypeScript files
---
## Critical Rules - Zero Tolerance
### 1. Strict TypeScript Configuration
**Required `tsconfig.json` settings:**
```json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"moduleResolution": "NodeNext",
"module": "NodeNext",
"target": "ES2022",
"declaration": true,
"declarationMap": true,
"sourceMap": true
}
}
```
### 2. No `any` - Ever
```typescript
// ❌ FORBIDDEN
function process(data: any) { ... }
const result: any = await fetch();
// ✅ REQUIRED
function process(data: unknown) { ... }
function process<T extends Record<string, unknown>>(data: T) { ... }
// Use type guards
function isValidResponse(data: unknown): data is ApiResponse {
return typeof data === 'object' && data !== null && 'status' in data;
}
```
### 3. Explicit Return Types
```typescript
// ❌ FORBIDDEN
async function getData() {
return await db.query();
}
// ✅ REQUIRED
async function getData(): Promise<User[]> {
return await db.query();
}
```
### 4. Null Safety
```typescript
// ❌ FORBIDDEN
const name = user.profile.name; // Could be undefined
// ✅ REQUIRED - Optional chaining + nullish coalescing
const name = user?.profile?.name ?? 'Unknown';
// ✅ REQUIRED - Early return pattern
if (!user?.profile?.name) {
throw new Error('User profile name is required');
}
const name = user.profile.name;
```
---
## Performance Patterns
### 1. Async/Await Best Practices
```typescript
// ❌ SLOW - Sequential
const user = await getUser(id);
const posts = await getPosts(id);
const comments = await getComments(id);
// ✅ FAST - Parallel
const [user, posts, comments] = await Promise.all([
getUser(id),
getPosts(id),
getComments(id),
]);
// ✅ CONTROLLED - Promise.allSettled for fault tolerance
const results = await Promise.allSettled([
fetchFromService1(),
fetchFromService2(),
fetchFromService3(),
]);
const successful = results
.filter((r): r is PromiseFulfilledResult<Data> => r.status === 'fulfilled')
.map(r => r.value);
```
### 2. Streaming for Large Data
```typescript
import { createReadStream, createWriteStream } from 'fs';
import { pipeline } from 'stream/promises';
import { Transform } from 'stream';
// ❌ BAD - Loads entire file into memory
const content = await fs.readFile('large-file.json', 'utf-8');
const data = JSON.parse(content);
// ✅ GOOD - Stream processing
async function processLargeFile(inputPath: string, outputPath: string): Promise<void> {
const transform = new Transform({
objectMode: true,
transform(chunk, encoding, callback) {
const processed = processChunk(chunk);
callback(null, processed);
},
});
await pipeline(
createReadStream(inputPath),
transform,
createWriteStream(outputPath)
);
}
```
### 3. Memory-Efficient Collections
```typescript
// ❌ BAD - Creates intermediate arrays
const result = data
.filter(x => x.active)
.map(x => x.id)
.slice(0, 10);
// ✅ GOOD - Generator for lazy evaluation
function* filterAndMap<T, U>(
items: Iterable<T>,
predicate: (item: T) => boolean,
mapper: (item: T) => U,
limit = Infinity
): Generator<U> {
let count = 0;
for (const item of items) {
if (count >= limit) return;
if (predicate(item)) {
yield mapper(item);
count++;
}
}
}
const result = [...filterAndMap(data, x => x.active, x => x.id, 10)];
```
---
## Error Handling
### 1. Custom Error Classes
```typescript
// Define error hierarchy
export class AppError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly statusCode: number = 500,
public readonly isOperational: boolean = true
) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
}
}
export class ValidationError extends AppError {
constructor(message: string, public readonly field?: string) {
super(message, 'VALIDATION_ERROR', 400);
}
}
export class NotFoundError extends AppError {
constructor(resource: string, id: string) {
super(`${resource} with id ${id} not found`, 'NOT_FOUND', 404);
}
}
```
### 2. Result Pattern (No Throw for Expected Failures)
```typescript
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
async function parseConfig(path: string): Promise<Result<Config, string>> {
try {
const content = await fs.readFile(path, 'utf-8');
const config = JSON.parse(content);
if (!isValidConfig(config)) {
return { success: false, error: 'Invalid configuration format' };
}
return { success: true, data: config };
} catch (e) {
return { success: false, error: `Failed to read config: ${e}` };
}
}
// Usage
const result = await parseConfig('.config.json');
if (!result.success) {
console.error(result.error);
process.exit(1);
}
console.log(result.data);
```
---
## CLI Development Patterns
### 1. Commander.js Structure
```typescript
import { Command, Option } from 'commander';
const program = new Command()
.name('my-cli')
.description('CLI description')
.version('1.0.0', '-v, --version');
// Subcommand with options
program
.command('generate')
.description('Generate output files')
.argument('<input>', 'Input file path')
.option('-o, --output <path>', 'Output path', './output')
.option('-f, --format <type>', 'Output format', 'json')
.option('--dry-run', 'Preview without writing', false)
.addOption(
new Option('-l, --log-level <level>', 'Log level')
.choices(['debug', 'info', 'warn', 'error'])
.default('info')
)
.action(async (input: string, options: GenerateOptions) => {
try {
await runGenerate(input, options);
} catch (error) {
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : error}`));
process.exit(1);
}
});
program.parseAsync();
```
### 2. User Feedback
```typescript
import ora from 'ora';
import chalk from 'chalk';
async function runWithSpinner<T>(
message: string,
task: () => Promise<T>
): Promise<T> {
const spinner = ora(message).start();
try {
const result = await task();
spinner.succeed();
return result;
} catch (error) {
spinner.fail();
throw error;
}
}
// Progress for multi-step operations
async function processFiles(files: string[]): Promise<void> {
const total = files.length;
for (let i = 0; i < files.length; i++) {
const file = files[i]!;
process.stdout.write(`\r${chalk.cyan('Processing')} [${i + 1}/${total}] ${file}`);
await processFile(file);
}
console.log(chalk.green('\n✔ All files processed'));
}
```
---
## Module Organization
### 1. Barrel Exports
```typescript
// types/index.ts - Export all types
export type { Config, Options, Result } from './config.js';
export type { User, UserProfile } from './user.js';
// Use in imports
import type { Config, User } from './types/index.js';
```
### 2. Dependency Injection
```typescript
// Define interfaces
interface Logger {
info(message: string): void;
error(message: string, error?: Error): void;
}
interface Database {
query<T>(sql: string, params?: unknown[]): Promise<T[]>;
}
// Service with injected dependencies
class UserService {
constructor(
private readonly db: Database,
private readonly logger: Logger
) {}
async getUser(id: string): Promise<User | null> {
this.logger.info(`Fetching user ${id}`);
const [user] = await this.db.query<User>('SELECT * FROM users WHERE id = ?', [id]);
return user ?? null;
}
}
```
---
## Testing Standards
### 1. Vitest Configuration
```typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
environment: 'node',
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
thresholds: {
lines: 80,
functions: 80,
branches: 75,
statements: 80,
},
},
include: ['src/**/*.test.ts'],
typecheck: {
enabled: true,
include: ['src/**/*.test.ts'],
},
},
});
```
### 2. Test Patterns
```typescript
import { describe, it, expect, vi, beforeEach } from 'vitest';
describe('UserService', () => {
let service: UserService;
let mockDb: Database;
let mockLogger: Logger;
beforeEach(() => {
mockDb = {
query: vi.fn(),
};
mockLogger = {
info: vi.fn(),
error: vi.fn(),
};
service = new UserService(mockDb, mockLogger);
});
it('should return user when found', async () => {
const expectedUser: User = { id: '1', name: 'Test' };
vi.mocked(mockDb.query).mockResolvedValue([expectedUser]);
const result = await service.getUser('1');
expect(result).toEqual(expectedUser);
expect(mockLogger.info).toHaveBeenCalledWith('Fetching user 1');
});
it('should return null when user not found', async () => {
vi.mocked(mockDb.query).mockResolvedValue([]);
const result = await service.getUser('999');
expect(result).toBeNull();
});
});
```
---
## Code Review Checklist
Before completing ANY TypeScript work:
- [ ] `strict: true` in tsconfig.json
- [ ] No `any` types (use `unknown` + type guards)
- [ ] All functions have explicit return types
- [ ] Errors use custom error classes or Result pattern
- [ ] Async operations use Promise.all where possible
- [ ] Large data uses streaming
- [ ] All exports have JSDoc comments
- [ ] Tests cover happy path, edge cases, and error cases
- [ ] `npm run lint` passes
- [ ] `npm run test` passes
- [ ] No console.log (use proper logger)
---
## Quick Reference
```typescript
// Type assertions (prefer type guards)
const data = value as Data; // ❌ Avoid
if (isData(value)) { ... } // ✅ Prefer
// Object destructuring with defaults
const { name = 'default', age } = user;
// Array methods with type narrowing
const numbers = mixed.filter((x): x is number => typeof x === 'number');
// Readonly for immutability
function process(items: readonly Item[]): void { ... }
// Template literal types
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type Endpoint = `/${string}`;
type Route = `${HttpMethod} ${Endpoint}`;
```Related Skills
openapi-to-typescript
Converts OpenAPI 3.0 JSON/YAML to TypeScript interfaces and type guards. This skill should be used when the user asks to generate types from OpenAPI, convert schema to TS, create API interfaces, or generate TypeScript types from an API specification.
typescript-pro
Master TypeScript with advanced types, generics, and strict type safety. Handles complex type systems, decorators, and enterprise-grade patterns. Use PROACTIVELY for TypeScript architecture, type inference optimization, or advanced typing patterns.
typescript-expert
TypeScript and JavaScript expert with deep knowledge of type-level programming, performance optimization, monorepo management, migration strategies, and modern tooling. Use PROACTIVELY for any TypeScript/JavaScript issues including complex type gymnastics, build performance, debugging, and architectural decisions. If a specialized expert is a better fit, I will recommend switching and stop.
typescript-advanced-types
Master TypeScript's advanced type system including generics, conditional types, mapped types, template literals, and utility types for building type-safe applications. Use when implementing complex type logic, creating reusable type utilities, or ensuring compile-time type safety in TypeScript projects.
threat-modeling-expert
Expert in threat modeling methodologies, security architecture review, and risk assessment. Masters STRIDE, PASTA, attack trees, and security requirement extraction. Use for security architecture reviews, threat identification, and secure-by-design planning.
service-mesh-expert
Expert service mesh architect specializing in Istio, Linkerd, and cloud-native networking patterns. Masters traffic management, security policies, observability integration, and multi-cluster mesh con
react-flow-node-ts
Create React Flow node components with TypeScript types, handles, and Zustand integration. Use when building custom nodes for React Flow canvas, creating visual workflow editors, or implementing node-based UI components.
prisma-expert
Prisma ORM expert for schema design, migrations, query optimization, relations modeling, and database operations. Use PROACTIVELY for Prisma schema issues, migration problems, query performance, relation design, or database connection issues.
nosql-expert
Expert guidance for distributed NoSQL databases (Cassandra, DynamoDB). Focuses on mental models, query-first modeling, single-table design, and avoiding hot partitions in high-scale systems.
nodejs-best-practices
Node.js development principles and decision-making. Framework selection, async patterns, security, and architecture. Teaches thinking, not copying.
nodejs-backend-patterns
Build production-ready Node.js backend services with Express/Fastify, implementing middleware patterns, error handling, authentication, database integration, and API design best practices. Use when creating Node.js servers, REST APIs, GraphQL backends, or microservices architectures.
nestjs-expert
Nest.js framework expert specializing in module architecture, dependency injection, middleware, guards, interceptors, testing with Jest/Supertest, TypeORM/Mongoose integration, and Passport.js authentication. Use PROACTIVELY for any Nest.js application issues including architecture decisions, testing strategies, performance optimization, or debugging complex dependency injection problems. If a specialized expert is a better fit, I will recommend switching and stop.