# 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 = []; ``` ### 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; type PartialConfig = Partial; ``` --- ## 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(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 { private handlers = new Map(); public on( 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( 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(); 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( 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('.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 = ( data: GameEventPayloads[T] ) => void; class GameController { private eventHandlers = new Map[]>(); public on( event: T, handler: EventHandler ): void { if (!this.eventHandlers.has(event)) { this.eventHandlers.set(event, []); } this.eventHandlers.get(event)!.push(handler); } public emit( 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 = { theme: 'dark' }; const newConfig: GameConfig = { ...defaultConfig, ...updates }; // Readonly const frozenConfig: Readonly = defaultConfig; // frozenConfig.autoSave = false; // ❌ Error! // Pick specific properties type ThemeConfig = Pick; // { theme: string } // Omit properties type ConfigWithoutTimer = Omit; ``` ### Record and Map ```typescript // ✅ Record for object maps type PieceSymbols = Record; const symbols: PieceSymbols = { [PieceType.PAWN]: '♙', [PieceType.KNIGHT]: '♘', [PieceType.BISHOP]: '♗', [PieceType.ROOK]: '♖', [PieceType.QUEEN]: '♕', [PieceType.KING]: '♔' }; // ✅ Map for runtime mapping const piecesByPosition = new Map(); // 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 = {}; 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**