Claude
Skills
Sign in
Back

typescript

Included with Lifetime
$97 forever

Type-safe development patterns for JARVIS AI Assistant

General

What this skill does


# TypeScript Development Skill

> **File Organization**: This skill uses split structure. See `references/` for advanced patterns and security examples.

## 1. Overview

This skill provides TypeScript expertise for the JARVIS AI Assistant, ensuring type safety across the entire codebase including Vue components, API routes, 3D rendering, and state management.

**Risk Level**: MEDIUM - Type system prevents runtime errors, enforces contracts, but misconfiguration can lead to security gaps

**Primary Use Cases**:
- Defining type-safe interfaces for JARVIS system data
- Runtime validation with Zod schemas
- Generic patterns for reusable HUD components
- Strict null checking to prevent crashes

## 2. Core Responsibilities

### 2.1 Fundamental Principles

1. **TDD First**: Write tests before implementation - red, green, refactor
2. **Performance Aware**: Apply memoization, lazy loading, and efficient patterns
3. **Strict Mode Always**: Enable all strict compiler options - no shortcuts
4. **Explicit Types at Boundaries**: Always type function parameters and return values at module boundaries
5. **Runtime Validation**: TypeScript types disappear at runtime - use Zod for external data
6. **No Any Escape Hatch**: Use `unknown` instead of `any`, then narrow with type guards
7. **Immutable by Default**: Prefer `readonly` and `as const` for data integrity
8. **Discriminated Unions**: Use tagged unions for state machines and error handling
9. **Branded Types**: Create nominal types for IDs and sensitive values

## 3. Technology Stack & Versions

### 3.1 Recommended Versions

| Package | Version | Security Notes |
|---------|---------|----------------|
| typescript | ^5.3.0 | Latest stable with improved type inference |
| zod | ^3.22.0 | Runtime validation, schema-first |
| @types/node | ^20.0.0 | Match Node.js version |

### 3.2 Compiler Configuration

```json
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "exactOptionalPropertyTypes": true,
    "noPropertyAccessFromIndexSignature": true,
    "forceConsistentCasingInFileNames": true,
    "verbatimModuleSyntax": true,
    "moduleResolution": "bundler",
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"]
  }
}
```

## 4. Implementation Patterns

### 4.1 Branded Types for Security

```typescript
// types/branded.ts
declare const __brand: unique symbol

type Brand<T, B> = T & { [__brand]: B }

// ✅ Prevent accidental mixing of IDs
export type UserId = Brand<string, 'UserId'>
export type SessionId = Brand<string, 'SessionId'>
export type CommandId = Brand<string, 'CommandId'>

// Factory functions with validation
export function createUserId(id: string): UserId {
  if (!/^usr_[a-zA-Z0-9]{16}$/.test(id)) {
    throw new Error('Invalid user ID format')
  }
  return id as UserId
}

// ✅ Type system prevents mixing IDs
function getUser(id: UserId): User { /* ... */ }
function getSession(id: SessionId): Session { /* ... */ }

// This won't compile:
// getUser(sessionId) // Error: SessionId not assignable to UserId
```

### 4.2 Discriminated Unions for State

```typescript
// types/jarvis-state.ts

// ✅ Type-safe state machine
type JARVISState =
  | { status: 'idle' }
  | { status: 'listening'; startTime: number }
  | { status: 'processing'; commandId: CommandId }
  | { status: 'responding'; response: string; confidence: number }
  | { status: 'error'; error: JARVISError; retryCount: number }

// ✅ Exhaustive handling
function handleState(state: JARVISState): string {
  switch (state.status) {
    case 'idle':
      return 'Ready'
    case 'listening':
      return `Listening for ${Date.now() - state.startTime}ms`
    case 'processing':
      return `Processing ${state.commandId}`
    case 'responding':
      return `${state.response} (${state.confidence}%)`
    case 'error':
      return `Error: ${state.error.message}`
    default:
      // ✅ Compile-time exhaustiveness check
      const _exhaustive: never = state
      return _exhaustive
  }
}
```

### 4.3 Runtime Validation with Zod

```typescript
// schemas/command.ts
import { z } from 'zod'

// ✅ Schema-first approach
export const commandSchema = z.object({
  id: z.string().regex(/^cmd_[a-zA-Z0-9]{16}$/),
  action: z.enum(['navigate', 'control', 'query', 'configure']),
  target: z.string().min(1).max(100),
  parameters: z.record(z.unknown()).optional(),
  timestamp: z.number().int().positive(),
  priority: z.number().min(0).max(10).default(5)
})

// ✅ Infer TypeScript type from schema
export type Command = z.infer<typeof commandSchema>

// ✅ Parse with full validation
export function parseCommand(data: unknown): Command {
  return commandSchema.parse(data)
}

// ✅ Safe parse for error handling
export function tryParseCommand(data: unknown): Command | null {
  const result = commandSchema.safeParse(data)
  return result.success ? result.data : null
}
```

### 4.4 Generic Patterns for HUD Components

```typescript
// ✅ Generic with constraints - ensures type safety for metrics
interface MetricConfig<T extends Record<string, number>> {
  metrics: T
  thresholds: { [K in keyof T]: { warning: number; critical: number } }
}

type SystemMetrics = { cpu: number; memory: number }
const config: MetricConfig<SystemMetrics> = {
  metrics: { cpu: 45, memory: 72 },
  thresholds: {
    cpu: { warning: 70, critical: 90 },
    memory: { warning: 80, critical: 95 }
  }
}
```

### 4.5 Type Guards for Narrowing

```typescript
// ✅ Type predicate for safe narrowing
function isSuccessResponse<T>(
  response: APIResponse<T>
): response is APIResponse<T> & { success: true; data: T } {
  return response.success && response.data !== undefined
}

// Usage - type automatically narrowed
if (isSuccessResponse(response)) {
  return response.data // ✅ Type is T, not T | undefined
}
```

### 4.6 Utility Types for JARVIS

```typescript
// types/utilities.ts

// ✅ Deep readonly for immutable state
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K]
}

// ✅ Make specific keys required
type RequireKeys<T, K extends keyof T> = T & Required<Pick<T, K>>

// ✅ Extract event payloads
type EventPayload<T> = T extends { payload: infer P } ? P : never

// ✅ Async function return type
type AsyncReturnType<T extends (...args: any[]) => Promise<any>> =
  T extends (...args: any[]) => Promise<infer R> ? R : never
```

## 5. Implementation Workflow (TDD)

### Step 1: Write Failing Test First

```typescript
// tests/utils/command-parser.test.ts
import { describe, it, expect } from 'vitest'
import { parseCommand } from '@/utils/command-parser'

describe('parseCommand', () => {
  it('should parse valid command', () => {
    expect(parseCommand('open settings')).toEqual({
      action: 'open', target: 'settings', parameters: {}
    })
  })

  it('should extract parameters', () => {
    expect(parseCommand('set volume to 80')).toEqual({
      action: 'set', target: 'volume', parameters: { value: 80 }
    })
  })

  it('should throw on empty command', () => {
    expect(() => parseCommand('')).toThrow('Command cannot be empty')
  })
})
```

### Step 2: Implement Minimum to Pass

Write only code needed to make tests green.

### Step 3: Refactor if Needed

Improve code quality while keeping tests green.

### Step 4: Run Full Verification

```bash
npx vitest run              # Unit tests
npx eslint . --ext .ts,.tsx # Linting
npx tsc --noEmit            # Type checking
```

## 6. Performance Patterns

### 6.1 Memoization

```typescript
// ❌ BAD - Recalculates on every render
const processed = data.map(item => heavyTransform(item))

// ✅ GOOD - Memoized computation
import { computed } from 'vue'
const processed = computed(() => data.value.map(item => heavyTransform(item)))
```

### 6.2 Lazy Loading

```typescript
// ❌ BAD - Loads everything upfront
import { HeavyChart } from '@/components/HeavyChart'

// ✅ GOOD - Lazy load heavy components
import { defineAsyncComponent } from 'vue'
const Heav

Related in General