typescript-javascript · git:20260812.4160717 · 2026-08-12 · sha256 4153a00231d9ef1a

typescript-javascript git:20260812.4160717A

Immutable. This exact content is served forever at /api/v1/blob/4153a00231d9ef1a.

---
name: typescript-javascript
description: TypeScript and JavaScript development standards for modern web and Node.js development. Covers strict TypeScript configuration, type safety patterns, ESM modules, async/await, testing with Jest/Vitest, and security best practices. Use when working with .ts, .tsx, .js, .mjs files, package.json, tsconfig.json, or when asking about TypeScript/JavaScript best practices.
---

# TypeScript & JavaScript Development

Mandatory gates are owned by the [JavaScript and TypeScript rule](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/rules/225-javascript-typescript.mdc). This skill and its references own procedures and examples.

## Guiding Principles

1. **Type Safety**: Leverage strict mode, avoid `any`, use discriminated unions
2. **Explicit Over Implicit**: Prefer explicit types for clarity and maintainability
3. **Modern Defaults**: ESM, const/let, async/await, optional chaining
4. **Security First**: Never use `eval`, sanitize HTML, validate inputs

## Quick Reference

| Aspect | TypeScript | JavaScript |
|--------|------------|------------|
| **Package Manager** | `pnpm` preferred | `pnpm` preferred |
| **Module System** | ES Modules | ES Modules + `// @ts-check` |
| **Linting** | `eslint --max-warnings=0` | `eslint --max-warnings=0` |
| **Formatting** | Prettier | Prettier |
| **Types** | Strict mode | JSDoc types |

## Non-Negotiables

### NN-1: Validate at trust boundaries

Static types do not validate runtime data. Treat HTTP bodies, responses, webhooks, queue messages, localStorage/sessionStorage, environment variables, CLI args, and JSON files as `unknown` until validated with Zod or an explicit type guard.

Reject:

- `JSON.parse(raw) as T`
- `await response.json() as T`
- unchecked property access on remote JSON
- `as any` or double assertions (`value as unknown as T`)

### NN-2: Fetch/API calls require timeout + status check + schema validation

Every service/network `fetch` must include a timeout, check `response.ok`, and validate the JSON shape before returning typed data.

```typescript
import { z } from 'zod';

async function fetchJson<T>(
  url: string,
  schema: z.ZodType<T>,
  options: RequestInit = {},
): Promise<T> {
  const response = await fetch(url, {
    ...options,
    signal: options.signal ?? AbortSignal.timeout(5_000),
    headers: { Accept: 'application/json', ...options.headers },
  });
  if (!response.ok) {
    throw new Error(`request failed: HTTP ${response.status}`);
  }
  return schema.parse(await response.json());
}
```

### NN-3: Production servers are hardened by default

Node/Express/Fastify services need bounded request bodies, explicit CORS, security headers, request IDs, structured logging, generic 5xx responses, and graceful shutdown. Do not use direct `app.listen(...)` examples for production services without retaining and closing the server.

### NN-4: Package manager and runtime are pinned

Declare `packageManager` and Node engine policy in `package.json`; CI uses Corepack and the declared package manager.

```json
{
  "packageManager": "pnpm@10.0.0",
  "engines": { "node": ">=22" }
}
```

## Critical Patterns

```typescript
// 1. Use strict equality
if (value === 0) { }        // ✅ GOOD
if (value == 0) { }         // ❌ BAD

// 2. Handle Promise rejections
fetchData().catch(err => console.error(err));  // ✅ GOOD

// 3. Optional chaining and nullish coalescing
const name = user?.profile?.name ?? 'Guest';  // ✅ GOOD

// 4. Use Set/Map for lookups
const seen = new Set();     // ✅ GOOD (O(1))
const seen = [];            // ❌ BAD (O(n))

// 5. Never use eval or new Function
eval(userInput);            // ❌ NEVER DO THIS

// 6. Sanitize HTML
element.textContent = userInput;  // ✅ GOOD
element.innerHTML = userInput;    // ❌ BAD (XSS)
```

## TypeScript Configuration

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noUncheckedIndexedAccess": true,
    "esModuleInterop": true,
    "skipLibCheck": false
  }
}
```

## Avoid `any` - Use Proper Types

```typescript
// ❌ BAD - Loses all type safety
function processData(data: any): any {
  return data.value;
}

// ✅ GOOD - Generic type
function processData<T>(data: T): T {
  return data;
}

// ✅ GOOD - Unknown for truly unknown types
function processData(data: unknown): string {
  if (typeof data === 'object' && data !== null && 'value' in data) {
    return String((data as { value: unknown }).value);
  }
  throw new Error('Invalid data');
}
```

## Discriminated Unions

```typescript
type SuccessResponse = {
  status: 'success';
  data: { id: string; name: string };
};

type ErrorResponse = {
  status: 'error';
  error: { code: number; message: string };
};

type ApiResponse = SuccessResponse | ErrorResponse;

function handleResponse(response: ApiResponse): void {
  if (response.status === 'success') {
    console.log(response.data.id);  // Type-safe
  } else {
    console.log(response.error.message);  // Type-safe
  }
}
```

## Utility Types

```typescript
interface User {
  id: string;
  name: string;
  email: string;
  password: string;
}

type UserUpdate = Partial<User>;           // All optional
type UserCredentials = Pick<User, 'email' | 'password'>;
type UserPublic = Omit<User, 'password'>;  // Exclude password
type RequiredUser = Required<User>;        // All required
type ReadonlyUser = Readonly<User>;        // Immutable
```

## Async Patterns

```typescript
// Parallel execution
const [users, products] = await Promise.all([
  fetchUsers(),
  fetchProducts()
]);

// Handle partial failures
const results = await Promise.allSettled([
  fetchUsers(),
  fetchProducts()
]);

results.forEach(result => {
  if (result.status === 'fulfilled') {
    console.log(result.value);
  } else {
    console.error(result.reason);
  }
});
```

## Security Rules (Mandatory)

- Never use `eval`, `new Function`, or unsanitized `innerHTML`
- Use `textContent` for DOM insertion
- Validate and sanitize all external inputs
- Do not log secrets/tokens/PII
- Use parameterized queries; no string-built queries
- Enforce HTTPS; secure cookies (HttpOnly, SameSite)

## Naming Conventions

| Type | Convention | Example |
|------|------------|---------|
| Functions/Variables | camelCase | `fetchUserData` |
| Classes/Interfaces | PascalCase | `UserService` |
| Constants | UPPER_SNAKE_CASE | `MAX_RETRIES` |
| Types | PascalCase | `ApiResponse` |

## Detailed References

- **TypeScript Patterns**: See [TypeScript patterns](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/typescript-javascript/references/typescript-patterns.md) for advanced types, generics, and mapped types
- **JavaScript Patterns**: See [JavaScript patterns](file:///Users/Devesh_Padmanabhan/.cursor/agent-engineering-handbook/skills/typescript-javascript/references/javascript-patterns.md) for JSDoc, ESM, and performance