DEV Community

myougaTheAxo
myougaTheAxo

Posted on

Supercharge Node.js/TypeScript Development with Claude Code: Setup, Skills, and Best Practices

Claude Code's default behavior is already good for TypeScript projects. With a few optimizations — a well-written CLAUDE.md, some custom hooks, and targeted skills — it becomes exceptional.

This guide covers the setup I use for production TypeScript backends.


1. CLAUDE.md for TypeScript Projects

The single most impactful thing you can do is write a solid CLAUDE.md:

# Project: my-api

## Stack
- Node.js 20 LTS + TypeScript 5.x
- Express 4 + Prisma ORM
- PostgreSQL 16

## Commands
- Test: `npm test` (Vitest)
- Lint: `npm run lint` (ESLint + Prettier)
- Build: `npm run build`
- DB migration: `npx prisma migrate dev`

## Architecture
- Layers: Router → Controller → Service → Repository
- No DB calls in Controllers
- No HTTP-specific code in Services
- Dependency injection via constructor parameters

## Code Rules
- Strict TypeScript (`strict: true` in tsconfig)
- No `any` type without explicit comment justification
- No `console.log` in production code (use `logger.ts`)
- All async functions must handle errors (try/catch or `.catch()`)
- Magic numbers must be named constants

## Security
- All SQL via Prisma ORM (no raw string queries)
- All external input validated with Zod
- No PII in logs
- Secrets only via `process.env`, never hardcoded

## Testing
- Test files: `src/**/*.test.ts`
- Coverage target: 80%
- Mock external services, never hit production APIs in tests
Enter fullscreen mode Exit fullscreen mode

2. TypeScript-Specific Hooks

Auto-format on write

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [{
          "type": "command",
          "command": "python .claude/hooks/ts_format.py"
        }]
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode
# .claude/hooks/ts_format.py
import json, subprocess, sys
from pathlib import Path

data = json.load(sys.stdin)
file_path = data.get("tool_input", {}).get("file_path", "")
if not file_path:
    sys.exit(0)

p = Path(file_path)
if p.suffix in (".ts", ".tsx", ".js", ".jsx"):
    subprocess.run(["npx", "prettier", "--write", str(p)], capture_output=True)
    subprocess.run(["npx", "eslint", "--fix", str(p)], capture_output=True)

sys.exit(0)
Enter fullscreen mode Exit fullscreen mode

Block console.log in source files

# .claude/hooks/no_console_log.py
import json, sys
from pathlib import Path

data = json.load(sys.stdin)
file_path = data.get("tool_input", {}).get("file_path", "")
content = data.get("tool_input", {}).get("content", "")

if not file_path or not file_path.endswith((".ts", ".js")):
    sys.exit(0)

if "src/" in file_path and "test" not in file_path:
    if "console.log(" in content and "// allow-console" not in content:
        print("[BLOCKED] console.log in source file. Use logger.ts instead.", file=sys.stderr)
        sys.exit(2)

sys.exit(0)
Enter fullscreen mode Exit fullscreen mode

3. Prisma-Aware Development

Claude Code handles Prisma well when you give it context. Add your schema path to CLAUDE.md:

## Database
- Schema: `prisma/schema.prisma`
- Client: `src/lib/db.ts` (singleton)
- Run migrations: `npx prisma migrate dev --name <description>`
Enter fullscreen mode Exit fullscreen mode

Then instructions like "add a refreshToken field to the User model" work correctly.


4. Testing with Vitest

Claude Code generates good Vitest tests when you specify:

## Testing Details
- Framework: Vitest
- Mocking: `vi.mock()` for modules, `vi.spyOn()` for methods
- Test pattern: AAA (Arrange, Act, Assert)
- No shared state between tests (`beforeEach` for setup)
Enter fullscreen mode Exit fullscreen mode

Run /test-gen src/services/user.ts and get tests that match your project's style.


5. Type Safety Patterns

Tell Claude Code to enforce specific TypeScript patterns:

## TypeScript Patterns
- Use `satisfies` instead of `as` for type assertions
- Prefer `readonly` arrays for function parameters
- Error types: use discriminated unions, not `Error` subclasses
- API responses: use `Result<T, E>` pattern, never throw from services

## Zod Schemas
- All API request bodies validated with Zod
- Schema files in `src/schemas/`
- Infer types from schemas: `type UserCreate = z.infer<typeof UserCreateSchema>`
Enter fullscreen mode Exit fullscreen mode

6. Common TypeScript Mistakes Claude Code Catches

With a well-written CLAUDE.md and /code-review, Claude Code reliably flags:

Issue Example
Floating promises fetchUser() without await
Type escape const x = value as any
Null assertion overuse user!.email
Missing error handling async function without try/catch
Implicit any from external APIs Missing type assertions on JSON.parse()

Setup Checklist

□ CLAUDE.md with stack, commands, rules, architecture
□ tsconfig.json with strict: true
□ ESLint + Prettier configured
□ Hooks for auto-format on write
□ Custom skill: /code-review for PR review
□ Custom skill: /test-gen for test coverage
Enter fullscreen mode Exit fullscreen mode

If you want pre-built skills instead of building from scratch, Code Review Pack (¥980) includes /code-review, /refactor-suggest, and /test-gen — all with TypeScript support.

👉 prompt-works.jp

Myouga (@myougatheaxo) — Security-focused Claude Code engineer.

Top comments (0)