# Typescript Type Safety

> Patterns for avoiding common TypeScript errors, proper type definitions, and early type checking workflows. Use when writing TypeScript code, encountering type errors, or before running tests. Prevents 50-60% of compilation errors and reduces fix cycles from 3-5 to 1-2.

- Skill: `pmarashian/typescript-type-safety` (Agent Skill)
- Install (CLI): `npx skillmds@latest add pmarashian/typescript-type-safety`
- Raw SKILL.md: https://api.skillmd.com/api/skills/pmarashian/typescript-type-safety/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: pmarashian (https://skillmd.com/u/pmarashian)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/pmarashian/typescript-type-safety

---


# TypeScript Type Safety

Patterns for avoiding common TypeScript errors, proper type definitions, and early type checking workflows. Prevents 50-60% of compilation errors.

## Overview

**Problem**: TypeScript errors discovered late, requiring 3-5 fix cycles

**Solution**: Early type checking, proper type definitions, and systematic error prevention

**Impact**: Reduce fix cycles from 3-5 to 1-2, save 30-60 seconds per task

## Early Type Checking Workflow

### Immediate Validation

**Run type-check immediately after code changes:**

```bash
# After making ANY TypeScript changes
npx tsc --noEmit

# Or use npm script
npm run type-check
```

**Workflow:**
1. Make code edit
2. Run `npx tsc --noEmit` **immediately**
3. Fix any errors
4. Continue with next edit or testing

**Timing:**
- **After file edits**: Run check immediately
- **Before browser testing**: Run check first
- **Before running tests**: Run check first
- **Before marking complete**: Run check to verify

## Common Error Patterns

### Pattern 1: Export/Import Validation

**Problem**: Missing exports for imported functions

**Solution**: Validate exports before imports

```typescript
// ❌ WRONG: Import without checking export
import { someFunction } from './utils';
// Error: Module has no exported member 'someFunction'

// ✅ CORRECT: Check export exists
// In utils.ts
export function someFunction() { }

// Then import
import { someFunction } from './utils';
```

**Validation pattern:**
```bash
# Before importing, check export exists
grep -r "export.*someFunction" src/
```

### Pattern 2: Type Conflicts

**Problem**: Type conflicts (class vs type names)

**Solution**: Use distinct names or proper type definitions

```typescript
// ❌ WRONG: Class and type with same name
class Settings { }
type Settings = { }; // Error: Duplicate identifier

// ✅ CORRECT: Use distinct names
class Settings { }
type SettingsData = { };

// Or use interface
interface SettingsData { }
```

### Pattern 3: Property Initialization

**Problem**: Property initialization in constructors

**Solution**: Initialize in constructor or mark as optional

```typescript
// ❌ WRONG: Uninitialized property
class GameScene {
  private player: Player; // Error: Property 'player' has no initializer
}

// ✅ CORRECT: Initialize in constructor
class GameScene {
  private player: Player;
  
  constructor() {
    this.player = new Player();
  }
}

// Or mark as optional
class GameScene {
  private player?: Player;
}
```

### Pattern 4: Global Type Extensions

**Problem**: Window extensions not typed

**Solution**: Declare global type extensions

```typescript
// ✅ CORRECT: Declare Window extension
declare global {
  interface Window {
    __TEST__?: {
      ready: boolean;
      sceneKey: string | null;
      gameState: () => any;
      commands: {
        [key: string]: (...args: any[]) => void;
      };
    };
  }
}
```

## Type Definition Patterns

### Global Type Extensions

**Window interface extensions:**

```typescript
declare global {
  interface Window {
    __TEST__?: {
      ready: boolean;
      sceneKey: string | null;
      seed: number | null;
      gameState: () => GameState;
      commands: TestCommands;
    };
    game?: Phaser.Game;
  }
}
```

### Union Types

**Flexible object types:**

```typescript
// Union type for flexible objects
type SpriteOrRectangle = Phaser.GameObjects.Sprite | Phaser.GameObjects.Rectangle;

function handleObject(obj: SpriteOrRectangle) {
  if (obj instanceof Phaser.GameObjects.Sprite) {
    // Sprite-specific code
  } else {
    // Rectangle-specific code
  }
}
```

### Discriminated Unions

**Better type safety with discriminated unions:**

```typescript
type GameEvent = 
  | { type: 'coin_collected'; value: number }
  | { type: 'timer_expired' }
  | { type: 'level_complete'; level: number };

function handleEvent(event: GameEvent) {
  switch (event.type) {
    case 'coin_collected':
      // event.value is available
      break;
    case 'timer_expired':
      // event.value is not available
      break;
    case 'level_complete':
      // event.level is available
      break;
  }
}
```

## Property Initialization Patterns

### Constructor Initialization

**Initialize all properties in constructor:**

```typescript
class GameScene extends Phaser.Scene {
  private player: Player;
  private score: number;
  private timer: number;

  constructor() {
    super({ key: 'GameScene' });
    // Initialize all properties
    this.player = new Player();
    this.score = 0;
    this.timer = 60;
  }
}
```

### Optional Properties

**Mark properties as optional if not initialized:**

```typescript
class GameScene extends Phaser.Scene {
  private player?: Player;
  private enemies?: Phaser.Physics.Arcade.Group;

  create() {
    // Initialize when needed
    this.player = new Player();
    this.enemies = this.physics.add.group();
  }
}
```

### Definite Assignment Assertion

**Use ! when property is definitely assigned later:**

```typescript
class GameScene extends Phaser.Scene {
  private player!: Player; // Definite assignment assertion

  create() {
    this.player = new Player(); // Assigned in create()
  }
}
```

## Export/Import Validation

### Check Exports Before Imports

**Validate exports exist:**

```bash
# Check if export exists
grep -r "export.*functionName" src/

# Check all exports in file
grep -r "^export" src/utils.ts
```

### Consistent Export Patterns

**Use consistent export patterns:**

```typescript
// ✅ CORRECT: Named export
export function utilityFunction() { }

// ✅ CORRECT: Default export
export default class MyClass { }

// ✅ CORRECT: Export list
export { function1, function2, class1 };

// ❌ WRONG: Mixing patterns inconsistently
export function func1() { }
export default function func2() { } // Confusing
```

## Common Error Fixes

### Missing Exports

**Error**: `Module has no exported member 'X'`

**Fix**:
1. Check if export exists in source file
2. Add export if missing
3. Verify export name matches import

```typescript
// In source file
export function myFunction() { }

// In importing file
import { myFunction } from './source';
```

### Type Conflicts

**Error**: `Duplicate identifier 'X'`

**Fix**:
1. Rename one of the conflicting types
2. Use namespace to separate
3. Use distinct names

```typescript
// Fix: Use distinct names
class Settings { }
type SettingsData = { };
```

### Property Initialization

**Error**: `Property 'X' has no initializer`

**Fix**:
1. Initialize in constructor
2. Mark as optional
3. Use definite assignment assertion

```typescript
// Fix 1: Initialize in constructor
constructor() {
  this.property = value;
}

// Fix 2: Mark as optional
private property?: Type;

// Fix 3: Definite assignment
private property!: Type;
```

## Workflow Integration

### Immediate Type Checking

**After code changes:**

```bash
# 1. Make code edit
edit_file("src/scenes/GameScene.ts", ...)

# 2. Run type-check immediately
npx tsc --noEmit

# 3. Fix errors if any
# 4. Continue with next edit
```

### Before Testing

**Always check types before testing:**

```bash
# Before browser testing
npx tsc --noEmit && agent-browser open http://localhost:3000

# Before running tests
npx tsc --noEmit && npm test
```

### Before Completion

**Verify types before marking complete:**

```bash
# Final type check
npx tsc --noEmit

# If passes, proceed with completion
```

## Best Practices

1. **Run type-check immediately** after code changes
2. **Fix errors systematically** (one type at a time)
3. **Validate exports** before importing
4. **Use proper type definitions** (global extensions, union types)
5. **Initialize properties** in constructor or mark optional
6. **Use discriminated unions** for better type safety
7. **Check types before testing** or marking complete

## Integration with Other Skills

- **typescript-incremental-check**: Uses early type checking workflow
- **pre-implementation-check**: Validates types before implementation
- **task-verification-workflow**: Includes type checking in verification

## Related Skills

- `typescript-incremental-check` - Fast type checking patterns
- `pre-implementation-check` - Pre-task verification
- `task-verification-workflow` - Task completion verification

## Remember

1. **Check types immediately** after code changes
2. **Fix errors systematically** before proceeding
3. **Validate exports** before importing
4. **Use proper type definitions** for global extensions
5. **Initialize properties** correctly
6. **Prevent 50-60%** of compilation errors

