# TypeScript Migration Code Examples

**Quick Reference Guide for Converting JavaScript to TypeScript**

---

## Table of Contents

1. [Basic Type Annotations](#1-basic-type-annotations)
2. [Interfaces vs Types](#2-interfaces-vs-types)
3. [Enums](#3-enums)
4. [Function Signatures](#4-function-signatures)
5. [Class Typing](#5-class-typing)
6. [Generics](#6-generics)
7. [Null Safety](#7-null-safety)
8. [DOM Typing](#8-dom-typing)
9. [Event Handling](#9-event-handling)
10. [Array and Object Typing](#10-array-and-object-typing)
11. [Import/Export](#11-importexport)
12. [Common Patterns](#12-common-patterns)

---

## 1. Basic Type Annotations

### Primitive Types

```typescript
// ❌ JavaScript
let name = 'Chess';
let age = 5;
let isActive = true;

// ✅ TypeScript (with inference - preferred)
let name = 'Chess';              // Type inferred as string
let age = 5;                     // Type inferred as number
let isActive = true;             // Type inferred as boolean

// ✅ TypeScript (explicit - when needed)
let name: string = 'Chess';
let age: number = 5;
let isActive: boolean = true;
```

### Arrays

```typescript
// ❌ JavaScript
const moves = [];
const pieces = [pawn, knight, bishop];

// ✅ TypeScript
const moves: Move[] = [];
const pieces: Piece[] = [pawn, knight, bishop];

// Alternative syntax
const moves: Array<Move> = [];
```

### Objects

```typescript
// ❌ JavaScript
const position = { row: 4, col: 4 };
const config = { autoSave: true, theme: 'dark' };

// ✅ TypeScript (inline type)
const position: { row: number; col: number } = { row: 4, col: 4 };

// ✅ TypeScript (using interface - preferred for reuse)
interface Position {
  row: number;
  col: number;
}

const position: Position = { row: 4, col: 4 };
```

---

## 2. Interfaces vs Types

### When to Use Interface

```typescript
// ✅ Use interface for object shapes and contracts
interface Position {
  row: number;
  col: number;
}

interface IPiece {
  color: Color;
  type: PieceType;
  position: Position;
  getValidMoves(board: Board): Position[];
}

// Interfaces can be extended
interface IKing extends IPiece {
  isInCheck: boolean;
  canCastle: boolean;
}

// Interfaces can be merged (declaration merging)
interface GameConfig {
  autoSave: boolean;
}

interface GameConfig {
  theme: string;  // Merged with above
}
```

### When to Use Type

```typescript
// ✅ Use type for unions
type Color = 'white' | 'black';
type GameStatus = 'active' | 'check' | 'checkmate' | 'stalemate';

// ✅ Use type for tuples
type Coordinate = [number, number];  // [row, col]

// ✅ Use type for intersections
type StyledPiece = IPiece & { cssClass: string };

// ✅ Use type for function signatures
type MoveValidator = (board: Board, move: Move) => boolean;

// ✅ Use type for complex mapped types
type ReadonlyPosition = Readonly<Position>;
type PartialConfig = Partial<GameConfig>;
```

---

## 3. Enums

### String Enums (Recommended)

```typescript
// ❌ JavaScript
const PIECE_TYPES = {
  PAWN: 'pawn',
  KNIGHT: 'knight',
  BISHOP: 'bishop',
  ROOK: 'rook',
  QUEEN: 'queen',
  KING: 'king'
};

// ✅ TypeScript
enum PieceType {
  PAWN = 'pawn',
  KNIGHT = 'knight',
  BISHOP = 'bishop',
  ROOK = 'rook',
  QUEEN = 'queen',
  KING = 'king'
}

// Usage
const piece = new Pawn();
piece.type = PieceType.PAWN;

// Type-safe comparisons
if (piece.type === PieceType.QUEEN) {
  // Queen-specific logic
}
```

### Const Enums (Performance)

```typescript
// ✅ For values that won't change at runtime
const enum Direction {
  NORTH = -1,
  SOUTH = 1,
  EAST = 1,
  WEST = -1
}

// Compiled away at build time - no runtime overhead
const row = position.row + Direction.NORTH;
```

### String Literal Union (Alternative)

```typescript
// ✅ Lighter weight than enum
type Color = 'white' | 'black';

// Usage is identical
const color: Color = 'white';

// Type-safe
const invalidColor: Color = 'red';  // ❌ Error!
```

---

## 4. Function Signatures

### Basic Functions

```typescript
// ❌ JavaScript
function isInBounds(row, col) {
  return row >= 0 && row < 8 && col >= 0 && col < 8;
}

// ✅ TypeScript
function isInBounds(row: number, col: number): boolean {
  return row >= 0 && row < 8 && col >= 0 && col < 8;
}

// Arrow function
const isInBounds = (row: number, col: number): boolean => {
  return row >= 0 && row < 8 && col >= 0 && col < 8;
};
```

### Optional Parameters

```typescript
// ❌ JavaScript
function makeMove(from, to, promotion) {
  promotion = promotion || 'queen';
  // ...
}

// ✅ TypeScript
function makeMove(
  from: Position,
  to: Position,
  promotion?: PieceType  // Optional parameter
): MoveResult {
  const promotionPiece = promotion ?? PieceType.QUEEN;
  // ...
}
```

### Default Parameters

```typescript
// ✅ TypeScript
function initGame(config: GameConfig = { autoSave: true }): void {
  // ...
}
```

### Rest Parameters

```typescript
// ❌ JavaScript
function captureMultiple(...pieces) {
  pieces.forEach(p => this.capture(p));
}

// ✅ TypeScript
function captureMultiple(...pieces: Piece[]): void {
  pieces.forEach(p => this.capture(p));
}
```

### Function Overloads

```typescript
// ✅ TypeScript - multiple signatures for same function
function getPiece(row: number, col: number): Piece | null;
function getPiece(position: Position): Piece | null;
function getPiece(
  rowOrPosition: number | Position,
  col?: number
): Piece | null {
  if (typeof rowOrPosition === 'number') {
    // row, col signature
    return this.grid[rowOrPosition][col!];
  } else {
    // Position signature
    return this.grid[rowOrPosition.row][rowOrPosition.col];
  }
}

// Usage
const piece1 = board.getPiece(4, 4);
const piece2 = board.getPiece({ row: 4, col: 4 });
```

---

## 5. Class Typing

### Basic Class

```typescript
// ❌ JavaScript
export class Piece {
  constructor(color, position) {
    this.color = color;
    this.position = position;
    this.type = null;
    this.hasMoved = false;
  }

  getValidMoves(board) {
    throw new Error('Must be implemented');
  }
}

// ✅ TypeScript
import { Color, Position, PieceType } from '@types';

export abstract class Piece implements IPiece {
  public readonly color: Color;
  public position: Position;
  public type: PieceType;
  public hasMoved: boolean = false;

  constructor(color: Color, position: Position) {
    this.color = color;
    this.position = position;
    this.type = PieceType.PAWN;  // Will be overridden by subclass
  }

  public abstract getValidMoves(board: Board): Position[];

  public isValidMove(board: Board, toRow: number, toCol: number): boolean {
    const validMoves = this.getValidMoves(board);
    return validMoves.some(move => move.row === toRow && move.col === toCol);
  }
}
```

### Inheritance

```typescript
// ✅ TypeScript
export class Pawn extends Piece {
  constructor(color: Color, position: Position) {
    super(color, position);
    this.type = PieceType.PAWN;
  }

  public override getValidMoves(board: Board): Position[] {
    const moves: Position[] = [];
    // Implementation
    return moves;
  }
}
```

### Access Modifiers

```typescript
export class GameController {
  // Public - accessible everywhere (default)
  public currentTurn: Color;

  // Private - accessible only within this class
  private selectedSquare: Position | null = null;

  // Protected - accessible in this class and subclasses
  protected board: Board;

  // Readonly - can only be assigned in constructor
  public readonly gameState: GameState;

  constructor() {
    this.currentTurn = Color.WHITE;
    this.board = new Board();
    this.gameState = new GameState();
  }

  // Private method
  private validateMove(move: Move): boolean {
    // Only accessible within GameController
    return true;
  }
}
```

### Static Members

```typescript
export class MoveValidator {
  // Static method - called on class, not instance
  public static isMoveLegal(
    board: Board,
    piece: Piece,
    toRow: number,
    toCol: number
  ): boolean {
    // ...
  }

  // Static property
  public static readonly MAX_BOARD_SIZE: number = 8;
}

// Usage
if (MoveValidator.isMoveLegal(board, piece, 4, 4)) {
  // ...
}
```

---

## 6. Generics

### Generic Functions

```typescript
// ❌ Non-generic
function cloneArray(arr) {
  return [...arr];
}

// ✅ Generic
function cloneArray<T>(arr: T[]): T[] {
  return [...arr];
}

// Usage - type is inferred
const pieces = [pawn, knight];
const clonedPieces = cloneArray(pieces);  // Type: Piece[]

const positions = [{ row: 0, col: 0 }];
const clonedPositions = cloneArray(positions);  // Type: Position[]
```

### Generic Classes

```typescript
// ✅ Generic event bus
export class EventBus<TEventMap> {
  private handlers = new Map<keyof TEventMap, Function[]>();

  public on<K extends keyof TEventMap>(
    event: K,
    handler: (data: TEventMap[K]) => void
  ): void {
    if (!this.handlers.has(event)) {
      this.handlers.set(event, []);
    }
    this.handlers.get(event)!.push(handler);
  }

  public emit<K extends keyof TEventMap>(
    event: K,
    data: TEventMap[K]
  ): void {
    const handlers = this.handlers.get(event) ?? [];
    handlers.forEach(handler => handler(data));
  }
}

// Usage with type-safe events
interface GameEvents {
  move: { from: Position; to: Position };
  capture: { piece: Piece };
  checkmate: { winner: Color };
}

const eventBus = new EventBus<GameEvents>();

eventBus.on('move', (data) => {
  // data is typed as { from: Position; to: Position }
  console.log(data.from, data.to);
});

eventBus.emit('checkmate', { winner: Color.WHITE });  // Type-safe!
```

### Generic Constraints

```typescript
// ✅ Constrain generic to have certain properties
interface HasPosition {
  position: Position;
}

function moveEntity<T extends HasPosition>(
  entity: T,
  newPosition: Position
): T {
  entity.position = newPosition;
  return entity;
}

// Works with any object that has a position property
moveEntity(pawn, { row: 5, col: 4 });
moveEntity(king, { row: 0, col: 4 });
```

---

## 7. Null Safety

### Strict Null Checks

```typescript
// ❌ JavaScript - can return null unexpectedly
function getPiece(row, col) {
  return this.grid[row][col];
}

const piece = getPiece(4, 4);
piece.getValidMoves(board);  // Runtime error if null!

// ✅ TypeScript - explicit null handling
function getPiece(row: number, col: number): Piece | null {
  if (!this.isInBounds(row, col)) {
    return null;
  }
  return this.grid[row][col];
}

const piece = getPiece(4, 4);
if (piece !== null) {
  // Type narrowing - piece is Piece here, not null
  piece.getValidMoves(board);
}
```

### Nullish Coalescing

```typescript
// ❌ JavaScript - falsy values problematic
const promotion = promotionType || 'queen';  // '' becomes 'queen'

// ✅ TypeScript - only null/undefined
const promotion = promotionType ?? PieceType.QUEEN;
```

### Optional Chaining

```typescript
// ❌ JavaScript - verbose null checks
const lastMove = this.gameState.moveHistory.length > 0
  ? this.gameState.moveHistory[this.gameState.moveHistory.length - 1]
  : null;
const notation = lastMove ? lastMove.notation : undefined;

// ✅ TypeScript - concise
const notation = this.gameState.getLastMove()?.notation;
```

### Non-null Assertion (Use Sparingly!)

```typescript
// ⚠️ Use only when you're absolutely certain value is not null
const piece = this.grid[row][col]!;  // ! asserts non-null
piece.getValidMoves(board);

// Better: Use type guard
if (this.grid[row][col] !== null) {
  const piece = this.grid[row][col];  // Type narrowed to Piece
  piece.getValidMoves(board);
}
```

---

## 8. DOM Typing

### DOM Elements

```typescript
// ❌ JavaScript
const board = document.getElementById('board');
board.addEventListener('click', (e) => {
  // ...
});

// ✅ TypeScript
const board = document.getElementById('board') as HTMLDivElement;
if (board !== null) {
  board.addEventListener('click', (e: MouseEvent) => {
    // e is typed as MouseEvent
  });
}

// Better: Use type guard
const board = document.getElementById('board');
if (board instanceof HTMLDivElement) {
  board.classList.add('active');
}
```

### Query Selectors

```typescript
// ❌ JavaScript
const squares = document.querySelectorAll('.square');

// ✅ TypeScript
const squares = document.querySelectorAll<HTMLDivElement>('.square');
squares.forEach((square) => {
  // square is typed as HTMLDivElement
  square.style.backgroundColor = 'red';
});
```

### Creating Elements

```typescript
// ✅ TypeScript
const square = document.createElement('div');  // HTMLDivElement
square.className = 'square';
square.dataset.row = '4';
square.dataset.col = '4';

const button = document.createElement('button');  // HTMLButtonElement
button.textContent = 'New Game';
button.onclick = () => this.startNewGame();
```

### Custom Data Attributes

```typescript
// ✅ TypeScript - extend HTMLElement interface
interface SquareElement extends HTMLDivElement {
  dataset: {
    row: string;
    col: string;
    color: 'light' | 'dark';
  };
}

function handleSquareClick(event: MouseEvent): void {
  const square = event.currentTarget as SquareElement;
  const row = parseInt(square.dataset.row);
  const col = parseInt(square.dataset.col);
  console.log(`Clicked ${square.dataset.color} square at ${row},${col}`);
}
```

---

## 9. Event Handling

### DOM Events

```typescript
// ❌ JavaScript
function handleClick(event) {
  const row = event.target.dataset.row;
  // ...
}

// ✅ TypeScript
function handleClick(event: MouseEvent): void {
  const target = event.target as HTMLElement;
  const row = target.dataset.row;

  // Better: check target type
  if (event.target instanceof HTMLElement) {
    const row = parseInt(event.target.dataset.row ?? '0');
  }
}
```

### Custom Events

```typescript
// ✅ Define event types
enum GameEvent {
  MOVE = 'move',
  CAPTURE = 'capture',
  CHECK = 'check',
  CHECKMATE = 'checkmate'
}

interface GameEventPayloads {
  [GameEvent.MOVE]: { move: Move; gameStatus: GameStatus };
  [GameEvent.CAPTURE]: { piece: Piece; position: Position };
  [GameEvent.CHECK]: { color: Color };
  [GameEvent.CHECKMATE]: { winner: Color };
}

// Type-safe event handlers
type EventHandler<T extends GameEvent> = (
  data: GameEventPayloads[T]
) => void;

class GameController {
  private eventHandlers = new Map<GameEvent, EventHandler<any>[]>();

  public on<T extends GameEvent>(
    event: T,
    handler: EventHandler<T>
  ): void {
    if (!this.eventHandlers.has(event)) {
      this.eventHandlers.set(event, []);
    }
    this.eventHandlers.get(event)!.push(handler);
  }

  public emit<T extends GameEvent>(
    event: T,
    data: GameEventPayloads[T]
  ): void {
    const handlers = this.eventHandlers.get(event) ?? [];
    handlers.forEach(handler => handler(data));
  }
}

// Usage - fully type-safe
const controller = new GameController();

controller.on(GameEvent.MOVE, (data) => {
  // data is typed as { move: Move; gameStatus: GameStatus }
  console.log('Move:', data.move.notation);
});

controller.emit(GameEvent.CHECKMATE, { winner: Color.WHITE });
```

---

## 10. Array and Object Typing

### Array Methods

```typescript
// ✅ Type-safe array methods
const pieces: Piece[] = board.getAllPieces();

// map - return type inferred
const positions: Position[] = pieces.map(p => p.position);

// filter - type narrowed
const whitePieces: Piece[] = pieces.filter(p => p.color === Color.WHITE);

// find - returns Piece | undefined
const queen: Piece | undefined = pieces.find(p => p.type === PieceType.QUEEN);

// some - returns boolean
const hasKing: boolean = pieces.some(p => p.type === PieceType.KING);

// reduce - with explicit return type
const totalValue: number = pieces.reduce((sum, p) => sum + p.value, 0);
```

### Object Manipulation

```typescript
// ✅ Type-safe object operations
interface GameConfig {
  autoSave: boolean;
  theme: string;
  enableTimer: boolean;
}

const defaultConfig: GameConfig = {
  autoSave: true,
  theme: 'light',
  enableTimer: false
};

// Partial updates
const updates: Partial<GameConfig> = {
  theme: 'dark'
};

const newConfig: GameConfig = { ...defaultConfig, ...updates };

// Readonly
const frozenConfig: Readonly<GameConfig> = defaultConfig;
// frozenConfig.autoSave = false;  // ❌ Error!

// Pick specific properties
type ThemeConfig = Pick<GameConfig, 'theme'>;  // { theme: string }

// Omit properties
type ConfigWithoutTimer = Omit<GameConfig, 'enableTimer'>;
```

### Record and Map

```typescript
// ✅ Record for object maps
type PieceSymbols = Record<PieceType, string>;

const symbols: PieceSymbols = {
  [PieceType.PAWN]: '♙',
  [PieceType.KNIGHT]: '♘',
  [PieceType.BISHOP]: '♗',
  [PieceType.ROOK]: '♖',
  [PieceType.QUEEN]: '♕',
  [PieceType.KING]: '♔'
};

// ✅ Map for runtime mapping
const piecesByPosition = new Map<string, Piece>();

// Type-safe get
const piece = piecesByPosition.get('e4');  // Piece | undefined

// Type-safe set
piecesByPosition.set('e4', pawn);
```

---

## 11. Import/Export

### Named Exports

```typescript
// ❌ JavaScript
export class Piece { }
export class Pawn extends Piece { }

// ✅ TypeScript - same syntax
export class Piece { }
export class Pawn extends Piece { }

// Import
import { Piece, Pawn } from './pieces';
```

### Type-Only Imports/Exports

```typescript
// ✅ Export types
export type { Position, Color, PieceType };
export interface IPiece { }

// Import types only (no runtime code)
import type { Position, Color } from '@types';
import type { IPiece } from '@types';

// Import both value and type
import { Board, type IBoard } from '@game/Board';
```

### Barrel Exports

```typescript
// src/types/index.ts
export * from './core.types';
export * from './piece.types';
export * from './game.types';
export * from './move.types';
export * from './ui.types';

// Usage
import { Position, Color, PieceType, Move, GameStatus } from '@types';
```

### Path Aliases

```typescript
// tsconfig.json
{
  "compilerOptions": {
    "paths": {
      "@/*": ["src/*"],
      "@types/*": ["src/types/*"],
      "@pieces/*": ["src/pieces/*"],
      "@game/*": ["src/game/*"]
    }
  }
}

// Usage
import { Pawn } from '@pieces/Pawn';
import { Board } from '@game/Board';
import { Position, Color } from '@types';
```

---

## 12. Common Patterns

### Singleton Pattern

```typescript
// ✅ TypeScript singleton
export class GameController {
  private static instance: GameController | null = null;

  private constructor() {
    // Private constructor prevents instantiation
  }

  public static getInstance(): GameController {
    if (GameController.instance === null) {
      GameController.instance = new GameController();
    }
    return GameController.instance;
  }
}

// Usage
const controller = GameController.getInstance();
```

### Factory Pattern

```typescript
// ✅ TypeScript factory
export class PieceFactory {
  public static createPiece(
    type: PieceType,
    color: Color,
    position: Position
  ): Piece {
    switch (type) {
      case PieceType.PAWN:
        return new Pawn(color, position);
      case PieceType.KNIGHT:
        return new Knight(color, position);
      case PieceType.BISHOP:
        return new Bishop(color, position);
      case PieceType.ROOK:
        return new Rook(color, position);
      case PieceType.QUEEN:
        return new Queen(color, position);
      case PieceType.KING:
        return new King(color, position);
      default:
        // Exhaustive check
        const exhaustiveCheck: never = type;
        throw new Error(`Unhandled piece type: ${exhaustiveCheck}`);
    }
  }
}
```

### Builder Pattern

```typescript
// ✅ TypeScript builder
export class GameConfigBuilder {
  private config: Partial<GameConfig> = {};

  public setAutoSave(autoSave: boolean): this {
    this.config.autoSave = autoSave;
    return this;
  }

  public setTheme(theme: string): this {
    this.config.theme = theme;
    return this;
  }

  public setEnableTimer(enableTimer: boolean): this {
    this.config.enableTimer = enableTimer;
    return this;
  }

  public build(): GameConfig {
    return {
      autoSave: this.config.autoSave ?? true,
      theme: this.config.theme ?? 'light',
      enableTimer: this.config.enableTimer ?? false
    };
  }
}

// Usage
const config = new GameConfigBuilder()
  .setAutoSave(false)
  .setTheme('dark')
  .build();
```

### Type Guards

```typescript
// ✅ Custom type guards
function isPawn(piece: Piece): piece is Pawn {
  return piece.type === PieceType.PAWN;
}

function isKing(piece: Piece): piece is King {
  return piece.type === PieceType.KING;
}

// Usage - type narrowing
const piece = board.getPiece(4, 4);
if (piece !== null && isPawn(piece)) {
  // piece is typed as Pawn here
  const enPassantMoves = piece.getEnPassantMoves(board, gameState);
}

if (piece !== null && isKing(piece)) {
  // piece is typed as King here
  const canCastle = piece.canCastleKingside(board);
}
```

### Discriminated Unions

```typescript
// ✅ Tagged union for type safety
interface NormalMove {
  type: 'normal';
  from: Position;
  to: Position;
}

interface CastleMove {
  type: 'castle';
  side: 'kingside' | 'queenside';
}

interface PromotionMove {
  type: 'promotion';
  from: Position;
  to: Position;
  promoteTo: PieceType;
}

type ChessMove = NormalMove | CastleMove | PromotionMove;

// Type-safe handling
function executeMove(move: ChessMove): void {
  switch (move.type) {
    case 'normal':
      // move is NormalMove here
      this.board.movePiece(move.from, move.to);
      break;
    case 'castle':
      // move is CastleMove here
      this.executeCastle(move.side);
      break;
    case 'promotion':
      // move is PromotionMove here
      this.board.movePiece(move.from, move.to);
      this.promotePawn(move.to, move.promoteTo);
      break;
  }
}
```

---

## Quick Reference Table

| JavaScript | TypeScript | When to Use |
|------------|------------|-------------|
| `let x = 5;` | `let x: number = 5;` | Explicit typing needed |
| `const arr = [];` | `const arr: Type[] = [];` | Empty arrays |
| `function f(x) {}` | `function f(x: Type): ReturnType {}` | All functions |
| `class C {}` | `class C implements I {}` | Class contracts |
| `const obj = {}` | `const obj: Interface = {}` | Object shapes |
| `'string'` literals | `'string' as const` | Const assertions |
| `null \|\| default` | `null ?? default` | Null/undefined only |
| `obj && obj.prop` | `obj?.prop` | Optional chaining |
| `obj.prop` | `obj!.prop` | Non-null assertion (careful!) |

---

**End of Examples Guide**
