Skill: jhauga/typescript-coder (version 3.0.0)

--- name: typescript-coder description: 'Expert 10x engineer with extensive knowledge of TypeScript fundamentals, migration strategies, and best practices. Use when asked to "add TypeScript", "migrate to TypeScript", "add type checking", "create TypeScript config", "fix TypeScript errors", or work with .ts/.tsx files. Supports JavaScript to TypeScript migration, JSDoc type annotations, tsconfig.json configuration, and type-safe code patterns.' --- # TypeScript Coder Skill Master TypeScript development with expert-level knowledge of type systems, migration strategies, and modern JavaScript/TypeScript patterns. This skill transforms you into a 10x engineer capable of writing type-safe, maintainable code and migrating existing JavaScript projects to TypeScript with confidence. ## When to Use This Skill - User asks to "add TypeScript", "migrate to TypeScript", or "convert to TypeScript" - Need to "add type checking" or "fix TypeScript errors" in a project - Creating or configuring `tsconfig.json` for a project - Working with `.ts`, `.tsx`, `.mts`, or `.d.ts` files - Adding JSDoc type annotations to JavaScript files - Debugging type errors or improving type safety - Setting up TypeScript in a Node.js or JavaScript project - Creating type definitions or ambient declarations - Implementing advanced TypeScript patterns (generics, conditional types, mapped types) ## Prerequisites - Basic understanding of JavaScript (ES6+) - Node.js and npm/yarn installed (for TypeScript compilation) - Familiarity with the project structure and build tools - Access to the `typescript` package (can be installed if needed) ## Shorthand Keywords Keywords to trigger this skill as if using a command-line tool: ```javascript openPrompt = ["typescript-coder", "ts-coder"] ``` Use these shorthand commands to quickly invoke TypeScript expertise without lengthy explanations. For example: - `typescript-coder --check "this code"` - `typescript-coder check this type guard` - `ts-coder migrate this file` - `ts-coder --migrate project-to-typescript` ## Role and Expertise As a TypeScript expert, you operate with: - **Deep Type System Knowledge**: Understanding of TypeScript's structural type system, generics, and advanced types - **Migration Expertise**: Proven strategies for incremental JavaScript to TypeScript migration - **Best Practices**: Knowledge of TypeScript patterns, conventions, and anti-patterns - **Tooling Mastery**: Configuration of TypeScript compiler, build tools, and IDE integration - **Problem Solving**: Ability to resolve complex type errors and design type-safe architectures ## Core TypeScript Concepts ### The TypeScript Type System TypeScript uses **structural typing** (duck typing) rather than nominal typing: ```typescript interface Point { x: number; y: number; } // This works because the object has the right structure const point: Point = { x: 10, y: 20 }; // This also works - structural compatibility const point3D = { x: 1, y: 2, z: 3 }; const point2D: Point = point3D; // OK - has x and y ``` ### Type Inference TypeScript infers types when possible, reducing boilerplate: ```typescript // Type inferred as string const message = "Hello, TypeScript!"; // Type inferred as number const count = 42; // Type inferred as string[] const names = ["Alice", "Bob", "Charlie"]; // Return type inferred as number function add(a: number, b: number) { return a + b; // Returns number } ``` ### Key TypeScript Features | Feature | Purpose | When to Use | |---------|---------|-------------| | **Interfaces** | Define object shapes | Defining data structures, API contracts | | **Type Aliases** | Create custom types | Union types, complex types, type utilities | | **Generics** | Type-safe reusable components | Functions/classes that work with multiple types | | **Enums** | Named constants | Fixed set of related values | | **Type Guards** | Runtime type checking | Narrowing union types safely | | **Utility Types** | Transform types | `Partial<T>`, `Pick<T, K>`, `Omit<T, K>`, etc. | ## Step-by-Step Workflows ### Task 1: Install and Configure TypeScript For a new or existing JavaScript project: 1. **Install TypeScript as a dev dependency**: ```bash npm install --save-dev typescript ``` 2. **Install type definitions for Node.js** (if using Node.js): ```bash npm install --save-dev @types/node ``` 3. **Initialize TypeScript configuration**: ```bash npx tsc --init ``` 4. **Configure `tsconfig.json`** for your project: ```json { "compilerOptions": { "target": "ES2020", "module": "commonjs", "lib": ["ES2020"], "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, [REDACTED_SECRET]: true, "resolveJsonModule": true, "declaration": true, "declarationMap": true, "sourceMap": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] } ``` 5. **Add build script to `package.json`**: ```json { "scripts": { "build": "tsc", "dev": "tsc --watch", "check": "tsc --noEmit" } } ``` ### Task 2: Migrate JavaScript to TypeScript (Incremental Approach) Safe, incremental migration strategy: 1. **Enable TypeScript to process JavaScript files**: ```json { "compilerOptions": { "allowJs": true, "checkJs": false, "noEmit": true } } ``` 2. **Add JSDoc type annotations to JavaScript files** (optional intermediate step): ```javascript // @ts-check /** * Calculates the sum of two numbers * @param {number} a - First number * @param {number} b - Second number * @returns {number} The sum */ function add(a, b) { return a + b; } /** @type {string[]} */ const names = ["Alice", "Bob"]; /** @typedef {{ id: number, name: string, email?: string }} User */ /** @type {User} */ const user = { id: 1, name: "Alice" }; ``` 3. **Rename files incrementally** from `.js` to `.ts`: ```bash # Start with utility files and leaf modules mv src/utils/helpers.js src/utils/helpers.ts ``` 4. **Fix TypeScript errors in converted files**: - Add explicit type annotations where inference fails - Define interfaces for complex objects - Handle `any` types appropriately - Add type guards for runtime checks 5. **Gradually convert remaining files**: - Start with utilities and shared modules - Move to leaf components (no dependencies) - Finally convert orchestration/entry files 6. **Enable strict mode progressively**: ```json { "compilerOptions": { "strict": false, "noImplicitAny": true, "strictNullChecks": true // Enable other strict flags one at a time } } ``` ### Task 3: Define Types and Interfaces Creating robust type definitions: 1. **Define interfaces for data structures**: ```typescript // User data model interface User { id: number; name: string; email: string; age?: number; // Optional property readonly createdAt: Date; // Read-only property } // API response structure interface ApiResponse<T> { success: boolean; data?: T; error?: { code: string; message: string; }; } ``` 2. **Use type aliases for complex types**: ```typescript // Union type type Status = 'pending' | 'active' | 'completed' | 'failed'; // Intersection type type Employee = User & { employeeId: string; department: string; salary: number; }; // Function type type TransformFn<T, U> = (input: T) => U; // Conditional type type NonNullable<T> = T extends null | undefined ? never : T; ``` 3. **Create type definitions in `.d.ts` files** for external modules: ```typescript // types/custom-module.d.ts declare module 'custom-module' { export interface Config { [REDACTED_SECRET]; timeout?: number; } export function initialize(config: Config): Promise<void>; export function fetchData<T>(endpoint: string): Promise<T>; } ``` ### Task 4: Work with Generics Type-safe reusable components: 1. **Generic functions**: ```typescript // Basic generic function function identity<T>(value: T): T { return value; } const num = identity(42); // Type: number const str = identity("hello"); // Type: string // Generic with constraints function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } const user = { name: "Alice", age: 30 }; const name = getProperty(user, "name"); // Type: string const age = getProperty(user, "age"); // Type: number ``` 2. **Generic classes**: ```typescript class DataStore<T> { private items: T[] = []; add(item: T): void { this.items.push(item); } get(index: number): T | undefined { return this.items[index]; } filter(predicate: (item: T) => boolean): T[] { return this.items.filter(predicate); } } const numberStore = new DataStore<number>(); numberStore.add(42); const userStore = new DataStore<User>(); userStore.add({ id: 1, name: "Alice", email: "[REDACTED_SECRET]" }); ``` 3. **Generic interfaces**: ```typescript interface Repository<T> { findById(id: string): Promise<T | null>; findAll(): Promise<T[]>; create(item: Omit<T, 'id'>): Promise<T>; update(id: string, item: Partial<T>): Promise<T>; delete(id: string): Promise<boolean>; } class UserRepository implements Repository<User> { async findById(id: string): Promise<User | null> { // Implementation return null; } // ... other methods } ``` ### Task 5: Handle Type Errors Common type errors and solutions: 1. **"Property does not exist" errors**: ```typescript // ❌ Error: Property 'name' does not exist on type '{}' const user = {}; user.name = "Alice"; // ✅ Solution 1: Define interface interface User { name: string; } const user: User = { name: "Alice" }; // ✅ Solution 2: Type assertion (use cautiously) const user = {} as User; user.name = "Alice"; // ✅ Solution 3: Index signature interface DynamicObject { [key: string]: any; } const user: DynamicObject = {}; user.name = "Alice"; ``` 2. **"Cannot find name" errors**: ```typescript // ❌ Error: Cannot find name 'process' const env = process.env.NODE_ENV; // ✅ Solution: Install type definitions // npm install --save-dev @types/node const env = process.env.NODE_ENV; // Now works ``` 3. **`any` type issues**: ```typescript // ❌ Implicit any (with noImplicitAny: true) function process(data) { return data.value; } // ✅ Solution: Add explicit types function process(data: { value: number }): number { return data.value; } // ✅ Or use generic function process<T>(data: T): T { return data; } ``` 4. **Union type narrowing**: ```typescript function processValue(value: string | number) { // ❌ Error: Property 'toUpperCase' does not exist on type 'string | number' return value.toUpperCase(); // ✅ Solution: Type guard if (typeof value === "string") { return value.toUpperCase(); // TypeScript knows it's string here } return value.toString(); } ``` ### Task 6: Configure for Specific Environments Environment-specific configurations: #### Node.js Project ```json { "compilerOptions": { "target": "ES2020", "module": "commonjs", "lib": ["ES2020"], "types": ["node"], "moduleResolution": "node", "esModuleInterop": true } } ``` #### Browser/DOM Project ```json { "compilerOptions": { "target": "ES2020", "module": "esnext", "lib": ["ES2020", "DOM", "DOM.Iterable"], "moduleResolution": "bundler", "resolveJsonModule": true, "noEmit": true } } ``` #### Library/Package ```json { "compilerOptions": { "target": "ES2020", "module": "esnext", "declaration": true, "declarationMap": true, "outDir": "./dist", "rootDir": "./src" } } ``` ## TypeScript Best Practices ### Do's - ✅ **Enable strict mode** (`"strict": true`) for maximum type safety - ✅ **Use type inference** - let TypeScript infer types when it's obvious - ✅ **Prefer interfaces over type aliases** for object shapes (better error messages) - ✅ **Use `unknown` instead of `any`** - forces type checking before use - ✅ **Create utility types** for common transformations - ✅ **Use const assertions** (`as const`) for literal types - ✅ **Leverage type guards** for runtime type checking - ✅ **Document complex types** with JSDoc comments - ✅ **Use discriminated unions** for type-safe state management - ✅ **Keep types DRY** - extract and reuse type definitions ### Don'ts - ❌ **Don't use `any` everywhere** - defeats the purpose of TypeScript - ❌ **Don't ignore TypeScript errors** with `@ts-ignore` without good reason - ❌ **Don't over-complicate types** - balance safety with readability - ❌ **Don't use type assertions excessively** - indicates design issues - ❌ **Don't duplicate type definitions** - use shared types - ❌ **Don't forget null/undefined checks** - enable `strictNullChecks` - ❌ **Don't use enums for everything** - consider union types instead - ❌ **Don't skip type definitions for external libraries** - install `@types/*` - ❌ **Don't disable strict flags without justification** - ❌ **Don't mix JavaScript and TypeScript in production** - complete the migration ## Common Patterns ### Pattern 1: Discriminated Unions Type-safe state management: ```typescript type LoadingState = { status: 'loading' }; type SuccessState<T> = { status: 'success'; data: T }; type ErrorState = { status: 'error'; error: Error }; type AsyncState<T> = LoadingState | SuccessState<T> | ErrorState; function handleState<T>(state: AsyncState<T>) { switch (state.status) { case 'loading': console.log('Loading...'); break; case 'success': console.log('Data:', state.data); // TypeScript knows state.data exists break; case 'error': console.log('Error:', state.error.message); // TypeScript knows state.error exists break; } } ``` ### Pattern 2: Builder Pattern Type-safe fluent API: ```typescript class QueryBuilder<T> { private filters: Array<(item: T) => boolean> = []; private sortFn?: (a: T, b: T) => number; private limitCount?: number; where(predicate: (item: T) => boolean): this { this.filters.push(predicate); return this; } sortBy(compareFn: (a: T, b: T) => number): this { this.sortFn = compareFn; return this; } limit(count: number): this { this.limitCount = count; return this; } execute(data: T[]): T[] { let result = data.filter(item => this.filters.every(filter => filter(item)) ); if (this.sortFn) { result = result.sort(this.sortFn); } if (this.limitCount) { result = result.slice(0, this.limitCount); } return result; } } // Usage const users = [/* ... */]; const result = new QueryBuilder<User>() .where(u => u.age > 18) .where(u => u.email.includes('@example.com')) .sortBy((a, b) => a.name.localeCompare(b.name)) .limit(10) .execute(users); ``` ### Pattern 3: Type-Safe Event Emitter ```typescript type EventMap = { 'user:created': { id: string; name: string }; 'user:updated': { id: string; changes: Partial<User> }; 'user:deleted': { id: string }; }; class TypedEventEmitter<T extends Record<string, any>> { private listeners: { [K in keyof T]?: Array<(data: T[K]) => void> } = {}; on<K extends keyof T>(event: K, listener: (data: T[K]) => void): void { if (!this.listeners[event]) { this.listeners[event] = []; } this.listeners[event]!.push(listener); } emit<K extends keyof T>(event: K, data: T[K]): void { const eventListeners = this.listeners[event]; if (eventListeners) { eventListeners.forEach(listener => listener(data)); } } } // Usage with type safety const emitter = new TypedEventEmitter<EventMap>(); emitter.on('user:created', (data) => { console.log(data.id, data.name); // TypeScript knows the shape }); emitter.emit('user:created', { id: '123', name: 'Alice' }); // Type-checked ``` ## Troubleshooting | Issue | Cause | Solution | |-------|-------|----------| | **Module not found** | Missing type definitions | Install `@types/[package-name]` or add `declare module` | | **Implicit any errors** | `noImplicitAny` enabled | Add explicit type annotations | | **Cannot find global types** | Missing lib in `compilerOptions` | Add to `lib`: `["ES2020", "DOM"]` | | **Type errors in node_modules** | Third-party library types | Add `skipLibCheck: true` to `tsconfig.json` | | **Import errors with .ts extension** | Import resolving issues | Use imports without extensions | | **Build takes too long** | Compiling too many files | Use `incremental: true` and `tsBuildInfoFile` | | **Type inference not working** | Complex inferred types | Add explicit type annotations | | **Circular dependency errors** | Import cycles | Refactor to break cycles, use interfaces | ## Advanced TypeScript Features ### Mapped Types Transform existing types: ```typescript type Readonly<T> = { readonly [P in keyof T]: T[P]; }; type Partial<T> = { [P in keyof T]?: T[P]; }; type Pick<T, K extends keyof T> = { [P in K]: T[P]; }; // Usage interface User { id: number; name: string; email: string; } type ReadonlyUser = Readonly<User>; // All properties readonly type PartialUser = Partial<User>; // All properties optional type UserNameEmail = Pick<User, 'name' | 'email'>; // Only name and email ``` ### Conditional Types Types that depend on conditions: ```typescript type IsString<T> = T extends string ? true : false; type A = IsString<string>; // true type B = IsString<number>; // false // Practical example: Extract function return type type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never; function getUser() { return { id: 1, name: "Alice" }; } type User = ReturnType<typeof getUser>; // { id: number; name: string } ``` ### Template Literal Types String manipulation at type level: ```typescript type Greeting<T extends string> = `Hello, ${T}!`; type WelcomeMessage = Greeting<"World">; // "Hello, World!" // Practical: Create event names type EventName<T extends string> = `on${Capitalize<T>}`; type ClickEvent = EventName<"click">; // "onClick" type HoverEvent = EventName<"hover">; // "onHover" ``` ## TypeScript Configuration Reference ### Key `tsconfig.json` Options | Option | Purpose | Recommended | |--------|---------|-------------| | `strict` | Enable all strict type checking | `true` | | `target` | ECMAScript target version | `ES2020` or higher | | `module` | Module system | `commonjs` (Node) or `esnext` (bundlers) | | `lib` | Include type definitions | `["ES2020"]` + `DOM` if browser | | `outDir` | Output directory | `./dist` | | `rootDir` | Root source directory | `./src` | | `sourceMap` | Generate source maps | `true` for debugging | | `declaration` | Generate .d.ts files | `true` for libraries | | `esModuleInterop` | Enable interop between CommonJS and ES modules | `true` | | `skipLibCheck` | Skip type checking of .d.ts files | `true` for performance | | [REDACTED_SECRET] | Enforce consistent file casing | `true` | | `resolveJsonModule` | Allow importing JSON files | `true` if needed | | `allowJs` | Allow JavaScript files | `true` during migration | | `checkJs` | Type check JavaScript files | `false` during migration | | `noEmit` | Don't emit files (use external bundler) | `true` with bundlers | | `incremental` | Enable incremental compilation | `true` for faster builds | ## Migration Checklist When migrating a JavaScript project to TypeScript: ### Phase 1: Setup - [ ] Install TypeScript and @types packages - [ ] Create `tsconfig.json` with permissive settings - [ ] Configure build scripts - [ ] Set up IDE/editor TypeScript support ### Phase 2: Incremental Migration - [ ] Enable `allowJs: true` and `checkJs: false` - [ ] Rename utility files to `.ts` - [ ] Add type annotations to function signatures - [ ] Create interfaces for data structures - [ ] Fix TypeScript errors in converted files ### Phase 3: Strengthen Types - [ ] Enable `noImplicitAny: true` - [ ] Enable `strictNullChecks: true` - [ ] Remove `any` types where possible - [ ] Add type guards for union types - [ ] Create type definitions for external modules ### Phase 4: Full Strict Mode - [ ] Enable `strict: true` - [ ] Fix all remaining type errors - [ ] Remove JSDoc annotations (now redundant) - [ ] Optimize type definitions - [ ] Document complex types ### Phase 5: Maintenance - [ ] Set up pre-commit type checking - [ ] Configure CI/CD type checking - [ ] Establish code review standards for types - [ ] Keep TypeScript and @types packages updated ## References This skill includes bundled reference documentation for TypeScript essentials. ### Reference Documentation (`references/`) #### Core Concepts & Fundamentals - **[basics.md](references/basics.md)** - TypeScript fundamentals, simple types, type inference, and special types - **[essentials.md](references/essentials.md)** - Core TypeScript concepts every developer should know - **[cheatsheet.md](references/cheatsheet.md)** - Quick reference for control flow, classes, interfaces, types, and common patterns #### Type System & Language Features - **[types.md](references/types.md)** - Advanced types, conditional types, mapped types, type guards, and recursive types - **[classes.md](references/classes.md)** - Class syntax, inheritance, generics, and utility types - **[elements.md](references/elements.md)** - Arrays, tuples, objects, enums, functions, and casting - **[keywords.md](references/keywords.md)** - keyof, null handling, optional chaining, and template literal types - **[miscellaneous.md](references/miscellaneous.md)** - Async programming, promises, decorators, and JSDoc integration ### External Resources - [TypeScript Official Documentation](https://www.typescriptlang.org/docs/) - [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html) - [TypeScript tsconfig Reference](https://www.typescriptlang.org/tsconfig/) - [TypeScript Deep Dive](https://basarat.gitbook.io/typescript/) - [TypeScript Playground](https://www.typescriptlang.org/play) - Test TypeScript code online ## Summary The TypeScript Coder skill empowers you to write type-safe, maintainable code with expert-level TypeScript knowledge. Whether migrating existing JavaScript projects or starting new TypeScript projects, apply these proven patterns, workflows, and best practices to deliver production-quality code with confidence. **Remember**: TypeScript is a tool for developer productivity and code quality. Use it to catch errors early, improve code documentation, and enable better tooling—but don't let perfect types prevent shipping working code.

path: references/basics.md
content: # TypeScript Basics

## TypeScript Tutorial

- Reference material for [Tutorial](https://www.w3schools.com/typescript/index.php)
- See [The TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html) for additional information

## Getting Started

### Most Basic Syntax

```ts
console.log('Hello World!');
```

- Reference material for [Getting Started](https://www.w3schools.com/typescript/typescript_getstarted.php)
- See [TS for the New Programmer](https://www.typescriptlang.org/docs/handbook/typescript-from-scratch.html) for additional information
- See [TypeScript for JS Programmers](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html) for additional information
- See [TS for Java/C# Programmers](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-oop.html) for additional information
- See [TS for Functional Programmers](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html) for additional information
- See [TypeScript Tooling in 5 minutes](https://www.typescriptlang.org/docs/handbook/typescript-tooling-in-5-minutes.html) for additional information

### Installing Compiler

```bash
npm install typescript --save-dev
```

```bash
added 1 package, and audited 2 packages in 2s
found 0 vulnerabilities
```

```bash
npx tsc
```

```bash
Version 4.5.5
tsc: The TypeScript Compiler - Version 4.5.5
```

### Configuring compiler

```bash
npx tsc --init
```

```ts
Created a new tsconfig.json with:
  target: es2016
  module: commonjs
  strict: true
  esModuleInterop: true
  skipLibCheck: true
  forceConsistentCasingInFileNames: true
```

### Configuration example

```json
{
  "include": ["src"],
  "compilerOptions": {
    "outDir": "./build"
  }
}
```

### Your First Program

```ts
function greet(name: string): string {
  return `Hello, ${name}!`;
}

const message: string = greet("World");
console.log(message);
```

### Compile and run

```bash
npx tsc hello.ts
```

### Compiled JavaScript output

```js
function greet(name) {
  return "Hello, ".concat(name, "!");
}

const message = greet("World");
console.log(message);
```

```bash
node hello.js
```

```
Hello, World!
```

## TypeScript Simple Types

- Reference material for [Simple Types](https://www.w3schools.com/typescript/typescript_simple_types.php)
- See [The Basics](https://www.typescriptlang.org/docs/handbook/2/basic-types.html) for additional information
- See [Everyday Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html) for additional information

### Boolean

```ts
let isActive: boolean = true;
let hasPermission = false; // TypeScript infers 'boolean' type
```

### Number

```ts
let decimal: number = 6;
let hex: number = 0xf00d;       // Hexadecimal
let binary: number = 0b1010;     // Binary
let octal: number = 0o744;      // Octal
let float: number = 3.14;      // Floating point
```

### String

```ts
let color: string = "blue";
let fullName: string = 'John Doe';
let age: number = 30;
let sentence: string = `Hello, my name is ${fullName} and I'll be ${age + 1} next year.`;
```

### BigInt (ES2020+)

```ts
const bigNumber: bigint = 9007199254740991n;
const hugeNumber = BigInt(9007199254740991); // Alternative syntax
```

### Symbol

```ts
const uniqueKey: symbol = Symbol('description');
const obj = {
  [uniqueKey]: 'This is a unique property'
};
console.log(obj[uniqueKey]); // "This is a unique property"
```

## TypeScript Explicit Types and Inference

- Reference material for [Explicit Types and Inference](https://www.w3schools.com/typescript/typescript_explicit_inference.php)
- See [Type Inference](https://www.typescriptlang.org/docs/handbook/type-inference.html) for additional information
- See [Variable Declaration](https://www.typescriptlang.org/docs/handbook/variable-declarations.html) for additional information

### Explicit Type Annotations

```ts
// String
let greeting: string = "Hello, TypeScript!";

// Number
let userCount: number = 42;

// Boolean
let isLoading: boolean = true;

// Array of numbers
let scores: number[] = [100, 95, 98];
```

```ts
// Function with explicit parameter and return types
function greet(name: string): string {
  return `Hello, ${name}!`;
}

// TypeScript will ensure you pass the correct argument type
greet("Alice"); // OK
greet(42);
// Error: Argument of type '42' is not assignable to parameter of type 'string'
```

### Type Inference

```ts
// TypeScript infers 'string'
let username = "alice";

// TypeScript infers 'number'
let score = 100;

// TypeScript infers 'boolean[]'
let flags = [true, false, true];

// TypeScript infers return type as 'number'
function add(a: number, b: number) {
  return a + b;
}
```

```ts
// TypeScript infers the shape of the object
const user = {
name: "Alice",
age: 30,
isAdmin: true
};

// TypeScript knows these properties exist
console.log(user.name);  // OK
console.log(user.email);
  // Error: Property 'email' does not exist
```

### Type Safety in Action

```ts
let username: string = "alice";
username = 42;
// Error: Type 'number' is not assignable to type 'string'
```

```ts
let score = 100;  // TypeScript infers 'number'
score = "high";
// Error: Type 'string' is not assignable to type 'number'
```

```ts
// This is valid JavaScript but can lead to bugs
function add(a, b) {
return a + b;
}

console.log(add("5", 3)); // Returns "53" (string concatenation)
```

```ts
function add(a: number, b: number): number {
return a + b;
}

console.log(add("5", 3));
// Error: Argument of type 'string' is not assignable to parameter of type 'number'
```

```ts
// 1. JSON.parse returns 'any' because the structure isn't known at compile time
const data = JSON.parse('{ "name": "Alice", "age": 30 }');

// 2. Variables declared without initialization
let something;  // Type is 'any'
something = 'hello';
something = 42;  // No error
```

## TypeScript Special Types

- Reference material for [Special Types](https://www.w3schools.com/typescript/typescript_special_types.php)
- See [Everyday Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html) for additional information
- See [Narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html) for additional information

### Type: any

```ts
let u = true;
u = "string";
// Error: Type 'string' is not assignable to type 'boolean'.
Math.round(u);
// Error: Argument of type 'boolean' is not assignable to parameter of type 'number'.
```

```ts
let v: any = true;
v = "string"; // no error as it can be "any" type
Math.round(v); // no error as it can be "any" type
```

### Type: unknown

```ts
let w: unknown = 1;
w = "string"; // no error
w = {
  runANonExistentMethod: () => {
    console.log("I think therefore I am");
  }
} as { runANonExistentMethod: () => void}
// How can we avoid the error for the code commented out below when
// we don't know the type?
// w.runANonExistentMethod(); // Error: Object is of type 'unknown'.
if(typeof w === 'object' && w !== null) {
  (w as { runANonExistentMethod: Function }).runANonExistentMethod();
}
// Although we have to cast multiple times we can do a check in the
// if to secure our type and have a safer casting
```

### Type: never

```ts
function throwError(message: string): never {
  throw new Error(message);
}
```

```ts
type Shape = Circle | Square | Triangle;

function getArea(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2;
    case 'square':
      return shape.sideLength ** 2;
    default:
      // TypeScript knows this should never happen
      const _exhaustiveCheck: never = shape;
      return _exhaustiveCheck;
  }
}
```

```ts
let x: never = true;
// Error: Type 'boolean' is not assignable to type 'never'.
```

### Type: undefined & null

```ts
let y: undefined = undefined;
let z: null = null;
```

```ts
// Optional parameter (implicitly `string | undefined`)
function greet(name?: string) {
  return `Hello, ${name || 'stranger'}`;
}

// Optional property in an interface
interface User {
  name: string;
  age?: number;  // Same as `number | undefined`
}
```

```ts
// Nullish coalescing (??) - only uses default
// if value is null or undefined
const value = input ?? 'default';

// Optional chaining (?.) - safely access nested properties
const street = user?.address?.street;
```


path: references/cheatsheet.md
content: # TypeScript Cheat Sheets

Quick reference guides for TypeScript features. These cheat sheets are based on the official TypeScript documentation.

## Control Flow Analysis

TypeScript's control flow analysis helps narrow types based on code structure.

### Type Guards

```typescript
// typeof type guards
function process(value: string | number) {
  if (typeof value === "string") {
    return value.toUpperCase(); // value is string
  }
  return value.toFixed(2); // value is number
}

// instanceof type guards
class Animal { name: string; }
class Dog extends Animal { bark(): void {} }

function handleAnimal(animal: Animal) {
  if (animal instanceof Dog) {
    animal.bark(); // animal is Dog
  }
}

// in operator
type Fish = { swim: () => void };
type Bird = { fly: () => void };

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    animal.swim(); // animal is Fish
  } else {
    animal.fly(); // animal is Bird
  }
}
```

### Truthiness Narrowing

```typescript
function printLength(str: string | null) {
  if (str) {
    console.log(str.length); // str is string
  }
}

// Falsy values: false, 0, -0, 0n, "", null, undefined, NaN
```

### Equality Narrowing

```typescript
function example(x: string | number, y: string | boolean) {
  if (x === y) {
    // x and y are both string
    x.toUpperCase();
    y.toUpperCase();
  }
}
```

### Discriminated Unions

```typescript
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; sideLength: number }
  | { kind: "triangle"; base: number; height: number };

function getArea(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.sideLength ** 2;
    case "triangle":
      return (shape.base * shape.height) / 2;
  }
}
```

### Assertion Functions

```typescript
function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new AssertionError(msg);
  }
}

function yell(str: string | undefined) {
  assert(str !== undefined, "str should be defined");
  // str is now string
  return str.toUpperCase();
}
```

## Classes

TypeScript class syntax and features.

### Basic Class

```typescript
class Point {
  x: number;
  y: number;

  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }

  distance(): number {
    return Math.sqrt(this.x ** 2 + this.y ** 2);
  }
}

const p = new Point(3, 4);
console.log(p.distance()); // 5
```

### Parameter Properties

```typescript
class Point {
  // Shorthand for declaring and initializing
  constructor(
    public x: number,
    public y: number
  ) {}
}
```

### Visibility Modifiers

```typescript
class BankAccount {
  private balance: number = 0;
  protected accountNumber: string;
  public owner: string;

  constructor(owner: string, accountNumber: string) {
    this.owner = owner;
    this.accountNumber = accountNumber;
  }

  public deposit(amount: number): void {
    this.balance += amount;
  }

  public getBalance(): number {
    return this.balance;
  }
}
```

### Readonly Properties

```typescript
class Person {
  readonly birthDate: Date;

  constructor(birthDate: Date) {
    this.birthDate = birthDate;
  }
}

const person = new Person(new Date(1990, 0, 1));
// person.birthDate = new Date(); // Error: readonly
```

### Inheritance

```typescript
class Animal {
  constructor(public name: string) {}

  move(distance: number): void {
    console.log(`${this.name} moved ${distance}m`);
  }
}

class Dog extends Animal {
  constructor(name: string, public breed: string) {
    super(name);
  }

  bark(): void {
    console.log("Woof!");
  }

  override move(distance: number): void {
    console.log("Running...");
    super.move(distance);
  }
}
```

### Abstract Classes

```typescript
abstract class Shape {
  abstract getArea(): number;

  describe(): string {
    return `Area: ${this.getArea()}`;
  }
}

class Circle extends Shape {
  constructor(public radius: number) {
    super();
  }

  getArea(): number {
    return Math.PI * this.radius ** 2;
  }
}
```

### Static Members

```typescript
class MathUtils {
  static PI: number = 3.14159;

  static circleArea(radius: number): number {
    return this.PI * radius ** 2;
  }
}

console.log(MathUtils.PI);
console.log(MathUtils.circleArea(5));
```

## Interfaces

Defining contracts for object shapes.

### Basic Interface

```typescript
interface User {
  id: number;
  name: string;
  email: string;
  age?: number; // optional
  readonly createdAt: Date; // readonly
}

const user: User = {
  id: 1,
  name: "Alice",
  email: "[REDACTED_SECRET]",
  createdAt: new Date()
};
```

### Function Types

```typescript
interface SearchFunc {
  (source: string, substring: string): boolean;
}

const search: SearchFunc = (src, sub) => {
  return src.includes(sub);
};
```

### Indexable Types

```typescript
interface StringArray {
  [index: number]: string;
}

const myArray: StringArray = ["Alice", "Bob"];

interface StringMap {
  [key: string]: number;
}

const ages: StringMap = {
  alice: 30,
  bob: 25
};
```

### Extending Interfaces

```typescript
interface Shape {
  color: string;
}

interface Square extends Shape {
  sideLength: number;
}

const square: Square = {
  color: "blue",
  sideLength: 10
};

// Multiple inheritance
interface Timestamped {
  createdAt: Date;
  updatedAt: Date;
}

interface Document extends Shape, Timestamped {
  title: string;
}
```

### Implementing Interfaces

```typescript
interface ClockInterface {
  currentTime: Date;
  setTime(d: Date): void;
}

class Clock implements ClockInterface {
  currentTime: Date = new Date();

  setTime(d: Date): void {
    this.currentTime = d;
  }
}
```

### Hybrid Types

```typescript
interface Counter {
  (start: number): string;
  interval: number;
  reset(): void;
}

function getCounter(): Counter {
  const counter = function(start: number) {
    return `Count: ${start}`;
  } as Counter;

  counter.interval = 123;
  counter.reset = function() {};

  return counter;
}
```

## Types

TypeScript's type system features.

### Primitive Types

```typescript
let isDone: boolean = false;
let decimal: number = 6;
let color: string = "blue";
let big: bigint = 100n;
let sym: symbol = Symbol("key");
let notDefined: undefined = undefined;
let empty: null = null;
```

### Array Types

```typescript
let list: number[] = [1, 2, 3];
let list2: Array<number> = [1, 2, 3];
let readonly: readonly number[] = [1, 2, 3];
```

### Tuple Types

```typescript
let tuple: [string, number] = ["hello", 10];
let labeled: [name: string, age: number] = ["Alice", 30];
let rest: [string, ...number[]] = ["items", 1, 2, 3];
```

### Union Types

```typescript
let value: string | number;
value = "hello";
value = 42;

type Status = "success" | "error" | "pending";
```

### Intersection Types

```typescript
type Person = { name: string };
type Employee = { employeeId: number };

type Staff = Person & Employee;

const staff: Staff = {
  name: "Alice",
  employeeId: 123
};
```

### Type Aliases

```typescript
type ID = string | number;
type Point = { x: number; y: number };
type Callback = (result: string) => void;
```

### Literal Types

```typescript
let direction: "north" | "south" | "east" | "west";
direction = "north"; // OK
// direction = "up"; // Error

type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
```

### Generic Types

```typescript
function identity<T>(arg: T): T {
  return arg;
}

interface Box<T> {
  value: T;
}

type Pair<T, U> = [T, U];

class DataStore<T> {
  private data: T[] = [];

  add(item: T): void {
    this.data.push(item);
  }
}
```

### Utility Types

```typescript
// Partial - make all properties optional
type PartialUser = Partial<User>;

// Required - make all properties required
type RequiredUser = Required<PartialUser>;

// Readonly - make all properties readonly
type ReadonlyUser = Readonly<User>;

// Pick - select specific properties
type UserPreview = Pick<User, "id" | "name">;

// Omit - exclude specific properties
type UserWithoutEmail = Omit<User, "email">;

// Record - create object type with specific keys
type Roles = Record<string, boolean>;

// ReturnType - extract function return type
type Result = ReturnType<typeof someFunction>;

// Parameters - extract function parameters
type Params = Parameters<typeof someFunction>;
```

### Mapped Types

```typescript
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

type Optional<T> = {
  [P in keyof T]?: T[P];
};

type Nullable<T> = {
  [P in keyof T]: T[P] | null;
};
```

### Conditional Types

```typescript
type IsString<T> = T extends string ? true : false;

type ExtractArray<T> = T extends (infer U)[] ? U : never;

type NonNullable<T> = T extends null | undefined ? never : T;
```

### Template Literal Types

```typescript
type Greeting = `Hello, ${string}`;
type EventName<T extends string> = `on${Capitalize<T>}`;

type Color = "red" | "blue" | "green";
type Size = "small" | "large";
type Style = `${Color}-${Size}`;
// "red-small" | "red-large" | "blue-small" | ...
```

---

**Reference Links:**

- [Control Flow Analysis](https://www.typescriptlang.org/static/TypeScript%20Control%20Flow%20Analysis-8a549253ad8470850b77c4c5c351d457.png)
- [Classes](https://www.typescriptlang.org/static/TypeScript%20Classes-83cc6f8e42ba2002d5e2c04221fa78f9.png)
- [Interfaces](https://www.typescriptlang.org/static/TypeScript%20Interfaces-34f1ad12132fb463bd1dfe5b85c5b2e6.png)
- [Types](https://www.typescriptlang.org/static/TypeScript%20Types-ae199d69aeecf7d4a2704a528d0fd3f9.png)
- [Download PDFs and PNGs](https://www.typescriptlang.org/assets/typescript-cheat-sheets.zip)


path: references/classes.md
content: # TypeScript Classes

## TypeScript Classes

- Reference material for [Classes](https://www.w3schools.com/typescript/typescript_classes.php)
- See [Classes](https://www.typescriptlang.org/docs/handbook/2/classes.html) for additional information
- See [Mixins](https://www.typescriptlang.org/docs/handbook/mixins.html) for additional information

### Members: Types

```ts
class Person {
  name: string;
}

const person = new Person();
person.name = "Jane";
```

### Members: Visibility

```ts
class Person {
  private name: string;

  public constructor(name: string) {
    this.name = name;
  }

  public getName(): string {
    return this.name;
  }
}

const person = new Person("Jane");
console.log(person.getName());
// person.name isn't accessible from outside the class since it's private
```

### Parameter Properties

```ts
class Person {
  // name is a private member variable
  public constructor(private name: string) {}

  public getName(): string {
    return this.name;
  }
}

const person = new Person("Jane");
console.log(person.getName());
```

### Readonly

```ts
class Person {
  private readonly name: string;

  public constructor(name: string) {
    // name cannot be changed after this initial definition, which has to be
    // either at its declaration or in the constructor.
    this.name = name;
  }

  public getName(): string {
    return this.name;
  }
}

const person = new Person("Jane");
console.log(person.getName());
```

### Inheritance: Implements

```ts
interface Shape {
  getArea: () => number;
}

class Rectangle implements Shape {
  public constructor(
    protected readonly width: number,
    protected readonly height: number
  ) {}

  public getArea(): number {
    return this.width * this.height;
  }
}
```

### Inheritance: Extends

```ts
interface Shape {
  getArea: () => number;
}

class Rectangle implements Shape {
  public constructor(protected readonly width: number, protected readonly height: number) {}

  public getArea(): number {
    return this.width * this.height;
  }
}

class Square extends Rectangle {
  public constructor(width: number) {
    super(width, width);
  }

  // getArea gets inherited from Rectangle
}
```

### Override

```ts
interface Shape {
  getArea: () => number;
}

class Rectangle implements Shape {
  // using protected for these members allows access from classes
  // that extend from this class, such as Square
  public constructor(
    protected readonly width: number,
    protected readonly height: number
  ) {}

  public getArea(): number {
    return this.width * this.height;
  }

  public toString(): string {
    return `Rectangle[width=${this.width}, height=${this.height}]`;
  }
}

class Square extends Rectangle {
  public constructor(width: number) {
    super(width, width);
  }

  // this toString replaces the toString from Rectangle
  public override toString(): string {
    return `Square[width=${this.width}]`;
  }
}
```

### Abstract Classes

```ts
abstract class Polygon {
  public abstract getArea(): number;

  public toString(): string {
    return `Polygon[area=${this.getArea()}]`;
  }
}

class Rectangle extends Polygon {
  public constructor(
    protected readonly width: number,
    protected readonly height: number
  ) {
    super();
  }

  public getArea(): number {
    return this.width * this.height;
  }
}
```

## TypeScript Basic Generics

- Reference material for [Basic Generics](https://www.w3schools.com/typescript/typescript_basic_generics.php)
- See [Generics](https://www.typescriptlang.org/docs/handbook/2/generics.html) for additional information
- See [Creating Types from Types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html) for additional information

### Functions

```ts
function createPair<S, T>(v1: S, v2: T): [S, T] {
  return [v1, v2];
}
console.log(createPair<string, number>('hello', 42)); // ['hello', 42]
```

### Classes

```ts
class NamedValue<T> {
  private _value: T | undefined;

  constructor(private name: string) {}

  public setValue(value: T) {
    this._value = value;
  }

  public getValue(): T | undefined {
    return this._value;
  }

  public toString(): string {
    return `${this.name}: ${this._value}`;
  }
}

let value = new NamedValue<number>('myNumber');
value.setValue(10);
console.log(value.toString()); // myNumber: 10
```

### Type Aliases

```ts
type Wrapped<T> = { value: T };

const wrappedValue: Wrapped<number> = { value: 10 };
```

### Default Value

```ts
class NamedValue<T = string> {
  private _value: T | undefined;

  constructor(private name: string) {}

  public setValue(value: T) {
    this._value = value;
  }

  public getValue(): T | undefined {
    return this._value;
  }

  public toString(): string {
    return `${this.name}: ${this._value}`;
  }
}

let value = new NamedValue('myNumber');
value.setValue('myValue');
console.log(value.toString()); // myNumber: myValue
```

### Extends Constraint

```ts
function createLoggedPair<S extends string | number, T extends string | number>(v1: S, v2: T): [S, T] {
  console.log(`creating pair: v1='${v1}', v2='${v2}'`);
  return [v1, v2];
}
```

## TypeScript Utility Types

- Reference material for [Utility Types](https://www.w3schools.com/typescript/typescript_utility_types.php)
- See [Utility Types](https://www.typescriptlang.org/docs/handbook/utility-types.html) for additional information

### Partial

```ts
interface Point {
  x: number;
  y: number;
}

let pointPart: Partial<Point> = {}; // `Partial` allows x and y to be optional
pointPart.x = 10;
```

### Required

```ts
interface Car {
  make: string;
  model: string;
  mileage?: number;
}

let myCar: Required<Car> = {
  make: 'Ford',
  model: 'Focus',
  mileage: 12000 // `Required` forces mileage to be defined
};
```

### Record

```ts
const nameAgeMap: Record<string, number> = {
  'Alice': 21,
  'Bob': 25
};
```

### Omit

```ts
interface Person {
  name: string;
  age: number;
  location?: string;
}

const bob: Omit<Person, 'age' | 'location'> = {
  name: 'Bob'
  // `Omit` has removed age and location from the type and they can't be defined here
};
```

### Pick

```ts
interface Person {
  name: string;
  age: number;
  location?: string;
}

const bob: Pick<Person, 'name'> = {
  name: 'Bob'
  // `Pick` has only kept name, so age and location were removed
  // from the type and they can't be defined here
};
```

### Exclude

```ts
type Primitive = string | number | boolean
const value: Exclude<Primitive, string> = true;
// a string cannot be used here since Exclude removed it from the type.
```

### ReturnType

```ts
type PointGenerator = () => { x: number; y: number; };
const point: ReturnType<PointGenerator> = {
  x: 10,
  y: 20
};
```

### Parameters

```ts
type PointPrinter = (p: { x: number; y: number; }) => void;
const point: Parameters<PointPrinter>[0] = {
  x: 10,
  y: 20
};
```

### Readonly

```ts
interface Person {
  name: string;
  age: number;
}
const person: Readonly<Person> = {
  name: "Dylan",
  age: 35,
};
person.name = 'Israel';
// prog.ts(11,8): error TS2540: Cannot assign to 'name' because it is a
// read-only property.
```


path: references/elements.md
content: # TypeScript Elements

## TypeScript Arrays

- Reference material for [Arrays](https://www.w3schools.com/typescript/typescript_arrays.php)
- See [Everyday Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html) for additional information

### Elements Syntax

```ts
const names: string[] = [];
names.push("Dylan"); // no error
// names.push(3);
// Error: Argument of type 'number' is not assignable to parameter of type 'string'.
```

### Readonly

```ts
const names: readonly string[] = ["Dylan"];
names.push("Jack");
// Error: Property 'push' does not exist on type 'readonly string[]'.
// try removing the readonly modifier and see if it works?
```

```ts
const numbers = [1, 2, 3]; // inferred to type number[]
numbers.push(4); // no error
// comment line below out to see the successful assignment
numbers.push("2");
// Error: Argument of type 'string' is not assignable to parameter of type 'number'.
let head: number = numbers[0]; // no error
```

## TypeScript Tuples

- Reference material for [Tuples](https://www.w3schools.com/typescript/typescript_tuples.php)
- See [Everyday Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html) for additional information

### Typed Arrays

```ts
// define our tuple
let ourTuple: [number, boolean, string];

// initialize correctly
ourTuple = [5, false, 'Coding God was here'];
```

```ts
// define our tuple
let ourTuple: [number, boolean, string];

// initialized incorrectly which throws an error
ourTuple = [false, 'Coding God was mistaken', 5];
```

### Readonly Tuple

```ts
// define our tuple
let ourTuple: [number, boolean, string];
// initialize correctly
ourTuple = [5, false, 'Coding God was here'];
// We have no type safety in our tuple for indexes 3+
ourTuple.push('Something new and wrong');
console.log(ourTuple);
```

```ts
// define our readonly tuple
const ourReadonlyTuple: readonly [number, boolean, string] =
 [5, true, 'The Real Coding God'];
// throws error as it is readonly.
ourReadonlyTuple.push('Coding God took a day off');
```

### Named Tuples

```ts
const graph: [x: number, y: number] = [55.2, 41.3];
```

```ts
const graph: [number, number] = [55.2, 41.3];
const [x, y] = graph;
```

## TypeScript Object Types

- Reference material for [Object Types](https://www.w3schools.com/typescript/typescript_object_types.php)
- See [Object Types](https://www.typescriptlang.org/docs/handbook/2/objects.html) for additional information
- See [Indexed Access Types](https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html) for additional information

### Elements Syntax

```ts
const car: { type: string, model: string, year: number } = {
  type: "Toyota",
  model: "Corolla",
  year: 2009
};
```

### Type Inference

```ts
const car = {
  type: "Toyota",
};
car.type = "Ford"; // no error
car.type = 2;
// Error: Type 'number' is not assignable to type 'string'.
```

### Optional Properties

```ts
const car: { type: string, mileage: number } = {
  // Error: Property 'mileage' is missing in type '{ type: string;}'
  // but required in type '{ type: string; mileage: number; }'.
  type: "Toyota",
};
car.mileage = 2000;
```

```ts
const car: { type: string, mileage?: number } = { // no error
  type: "Toyota"
};
car.mileage = 2000;
```

### Index Signatures

```ts
const nameAgeMap: { [index: string]: number } = {};
nameAgeMap.Jack = 25; // no error
nameAgeMap.Mark = "Fifty";
// Error: Type 'string' is not assignable to type 'number'.
```

## TypeScript Enums

- Reference material for [Enums](https://www.w3schools.com/typescript/typescript_enums.php)
- See [Enums](https://www.typescriptlang.org/docs/handbook/enums.html) for additional information

### Numeric Enums - Default

```ts
enum CardinalDirections {
  North,
  East,
  South,
  West
}
let currentDirection = CardinalDirections.North;
// logs 0
console.log(currentDirection);
// throws error as 'North' is not a valid enum
currentDirection = 'North';
// Error: "North" is not assignable to type 'CardinalDirections'.
```

### Numeric Enums - Initialized

```ts
enum CardinalDirections {
  North = 1,
  East,
  South,
  West
}
// logs 1
console.log(CardinalDirections.North);
// logs 4
console.log(CardinalDirections.West);
```

### Numeric Enums - Fully Initialized

```ts
enum StatusCodes {
  NotFound = 404,
  Success = 200,
  Accepted = 202,
  BadRequest = 400
}
// logs 404
console.log(StatusCodes.NotFound);
// logs 200
console.log(StatusCodes.Success);
```

### String Enums

```ts
enum CardinalDirections {
  North = 'North',
  East = "East",
  South = "South",
  West = "West"
};
// logs "North"
console.log(CardinalDirections.North);
// logs "West"
console.log(CardinalDirections.West);
```

## TypeScript Type Aliases and Interfaces

- Reference material for [Type Aliases and Interfaces](https://www.w3schools.com/typescript/typescript_aliases_and_interfaces.php)
- See [Everyday Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html) for additional information
- See [Object Types](https://www.typescriptlang.org/docs/handbook/2/objects.html) for additional information

### Type Aliases

```ts
type CarYear = number
type CarType = string
type CarModel = string
type Car = {
  year: CarYear,
  type: CarType,
  model: CarModel
}

const carYear: CarYear = 2001
const carType: CarType = "Toyota"
const carModel: CarModel = "Corolla"
const car: Car = {
  year: carYear,
  type: carType,
  model: carModel
};
```

```ts
type Animal = { name: string };
type Bear = Animal & { honey: boolean };
const bear: Bear = { name: "Winnie", honey: true };

type Status = "success" | "error";
let response: Status = "success";
```

### Interfaces

```ts
interface Rectangle {
  height: number,
  width: number
}

const rectangle: Rectangle = {
  height: 20,
  width: 10
};
```

```ts
interface Animal {
     name: string;
}
interface Animal {
  age: number;
}
const dog: Animal = {
  name: "Fido",
  age: 5
};
```

### Extending Interfaces

```ts
interface Rectangle {
  height: number,
  width: number
}

interface ColoredRectangle extends Rectangle {
  color: string
}

const coloredRectangle: ColoredRectangle = {
  height: 20,
  width: 10,
  color: "red"
};
```

## TypeScript Union Types

- Reference material for [Union Types](https://www.w3schools.com/typescript/typescript_union_types.php)
- See [Everyday Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html) for additional information
- See [Narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html) for additional information

### Union | (OR)

```ts
function printStatusCode(code: string | number) {
  console.log(`My status code is ${code}.`)
}
printStatusCode(404);
printStatusCode('404');
```

### Type Guards

```ts
function printStatusCode(code: string | number) {
  console.log(`My status code is ${code.toUpperCase()}.`)
  // error: Property 'toUpperCase' does not exist on type 'string | number'.
  // Property 'toUpperCase' does not exist on type 'number'
}
```

> [!NOTE]
> In our example we are having an issue invoking `toUpperCase()` as it's a string method and number doesn't have access to it.

## TypeScript Functions

- Reference material for [Functions](https://www.w3schools.com/typescript/typescript_functions.php)
- See [More on Functions](https://www.typescriptlang.org/docs/handbook/2/functions.html) for additional information

### Return Type

```ts
// the `: number` here specifies that this function returns a number
function getTime(): number {
  return new Date().getTime();
}
```

### Void Return Type

```ts
function printHello(): void {
  console.log('Hello!');
}
```

### Parameters

```ts
function multiply(a: number, b: number) {
  return a * b;
}
```

### Optional Parameters

```ts
// the `?` operator here marks parameter `c` as optional
function add(a: number, b: number, c?: number) {
  return a + b + (c || 0);
}
```

### Default Parameters

```ts
function pow(value: number, exponent: number = 10) {
  return value ** exponent;
}
```

### Named Parameters

```ts
function divide({ dividend, divisor }: { dividend: number, divisor: number }) {
  return dividend / divisor;
}
```

### Rest Parameters

```ts
function add(a: number, b: number, ...rest: number[]) {
  return a + b + rest.reduce((p, c) => p + c, 0);
}
```

### Type Alias

```ts
type Negate = (value: number) => number;

// in this function, the parameter `value` automatically gets assigned
// the type `number` from the type `Negate`
const negateFunction: Negate = (value) => value * -1;
```

## TypeScript Casting

- Reference material for [Casting](https://www.w3schools.com/typescript/typescript_casting.php)
- See [Type Compatibility](https://www.typescriptlang.org/docs/handbook/type-compatibility.html) for additional information

### Casting with as

```ts
let x: unknown = 'hello';
console.log((x as string).length);
```

### Casting with <>

```ts
let x: unknown = 'hello';
console.log((<string>x).length);
```

### Force Casting

```ts
let x = 'hello';
console.log(((x as unknown) as number).length);
// x is not actually a number so this will return undefined
```


path: references/essentials.md
content: # TypeScript Essentials

TypeScript reference material covering essential language features and concepts from the official TypeScript documentation.

## Utility Types

- Reference material for [Utility Types](https://www.typescriptlang.org/docs/handbook/utility-types.html)

Built-in generic types that transform existing types into new ones.

```ts
// Partial<T> — makes all properties optional
interface User { name: string; age: number; }
const update: Partial<User> = { name: "Alice" };

// Required<T> — makes all properties required
interface Config { timeout?: number; retries?: number; }
const config: Required<Config> = { timeout: 3000, retries: 3 };

// Readonly<T> — makes all properties read-only
const p: Readonly<{ x: number; y: number }> = { x: 1, y: 2 };
// p.x = 5; // Error

// Record<K, V> — key-value map type
type Roles = "admin" | "user" | "guest";
const permissions: Record<Roles, boolean> = { admin: true, user: false, guest: false };

// Pick<T, K> — select a subset of keys
type UserPreview = Pick<User, "name">;

// Omit<T, K> — remove a subset of keys
type PublicUser = Omit<{ id: number; name: string; [REDACTED_SECRET] }, "password">;

// Exclude<T, U> — remove union members assignable to U
type ActiveStatus = Exclude<"active" | "inactive" | "pending", "inactive" | "pending">;
// "active"

// Extract<T, U> — keep only union members assignable to U
type StringOrNumber = Extract<string | number | boolean, string | number>;

// NonNullable<T> — remove null and undefined
type DefiniteString = NonNullable<string | null | undefined>; // string

// ReturnType<T> — extract function return type
function getUser() { return { id: 1, name: "Alice" }; }
type UserType = ReturnType<typeof getUser>;

// Parameters<T> — extract function parameter types as a tuple
type Params = Parameters<(name: string, age: number) => void>;
// [name: string, age: number]

// InstanceType<T> — extract class instance type
class MyClass { x = 10; }
type Instance = InstanceType<typeof MyClass>;

// ConstructorParameters<T> — extract constructor parameters
class Point { constructor(public x: number, public y: number) {} }
type PointArgs = ConstructorParameters<typeof Point>; // [number, number]

// Awaited<T> — recursively unwrap Promise
type A = Awaited<Promise<Promise<number>>>; // number

// String manipulation
type Upper = Uppercase<"hello">;       // "HELLO"
type Lower = Lowercase<"WORLD">;       // "world"
type Cap   = Capitalize<"typescript">; // "Typescript"
type Uncap = Uncapitalize<"TypeScript">; // "typeScript"
```

Key utility types reference:

| Utility Type | Purpose |
|---|---|
| `Partial<T>` | All props optional |
| `Required<T>` | All props required |
| `Readonly<T>` | All props read-only |
| `Record<K,V>` | Key-value map type |
| `Pick<T,K>` | Select subset of keys |
| `Omit<T,K>` | Remove subset of keys |
| `Exclude<T,U>` | Remove union members |
| `Extract<T,U>` | Keep union members |
| `NonNullable<T>` | Remove null/undefined |
| `ReturnType<T>` | Function return type |
| `Parameters<T>` | Function param types |
| `InstanceType<T>` | Class instance type |
| `Awaited<T>` | Unwrap Promise type |

## Cheat Sheets

- Reference material for [Cheat Sheets](https://www.typescriptlang.org/cheatsheets/)

Four downloadable cheat sheets covering core TypeScript topics:

**Control Flow Analysis** — narrowing, type guards, `typeof`, `instanceof`, `in`, assignments, exhaustiveness checks.

**Types** — primitive types, unions, intersections, generics, utility types, mapped types, conditional types.

**Interfaces** — object shapes, optional/readonly properties, index signatures, extending, declaration merging.

**Classes** — constructors, fields, access modifiers (`public`, `private`, `protected`), `abstract`, generics, decorators.

```ts
// Control flow narrowing example
function padLeft(value: string, padding: string | number) {
  if (typeof padding === "number") {
    return " ".repeat(padding) + value; // padding: number
  }
  return padding + value; // padding: string
}

// Mapped type (from Types sheet)
type Optional<T> = { [K in keyof T]?: T[K] };

// Interface extending (from Interfaces sheet)
interface Animal { name: string; }
interface Dog extends Animal { breed: string; }

// Abstract class (from Classes sheet)
abstract class Shape {
  abstract getArea(): number;
  toString() { return `Area: ${this.getArea()}`; }
}
```

## Decorators

- Reference material for [Decorators](https://www.typescriptlang.org/docs/handbook/decorators.html)

Decorators are special declarations that attach to classes, methods, accessors, properties, or parameters. Require `"experimentalDecorators": true` in `tsconfig.json` for legacy decorators. TypeScript 5.0+ supports Stage 3 decorators without a flag.

```ts
// tsconfig.json (legacy decorators)
// { "compilerOptions": { "experimentalDecorators": true, "emitDecoratorMetadata": true } }

// Decorator factory — customizes the decorator
function color(value: string) {
  return function (target: any) {
    target.prototype.color = value;
  };
}

// Class decorator
function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

@sealed
@color("blue")
class BugReport {
  type = "report";
  title: string;
  constructor(t: string) { this.title = t; }
}

// Method decorator
function enumerable(value: boolean) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    descriptor.enumerable = value;
  };
}

class Greeter {
  @enumerable(false)
  greet() { return "Hello!"; }
}

// Property decorator (using reflect-metadata)
// import "reflect-metadata";
// const formatMetadataKey = Symbol("format");
// function format(formatString: string) {
//   return Reflect.metadata(formatMetadataKey, formatString);
// }

// Parameter decorator
function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
  // mark parameter as required via metadata
}

// TypeScript 5.0 Stage 3 decorator (no flag needed)
function loggedMethod(originalMethod: any, context: ClassMethodDecoratorContext) {
  const methodName = String(context.name);
  return function (this: any, ...args: any[]) {
    console.log(`Entering '${methodName}'`);
    const result = originalMethod.call(this, ...args);
    console.log(`Exiting '${methodName}'`);
    return result;
  };
}

class Person {
  name: string;
  constructor(name: string) { this.name = name; }

  @loggedMethod
  greet() { console.log(`Hello, my name is ${this.name}.`); }
}
```

Decorator evaluation order: multiple decorators on one declaration are evaluated top-down but applied bottom-up. Across a class: instance members first (parameter → method/accessor/property), then static members, then constructor parameters, then class decorators.

## Declaration Merging

- Reference material for [Declaration Merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html)

TypeScript merges two or more separate declarations with the same name into a single definition.

```ts
// Interface merging — merged into one interface
interface Box { height: number; width: number; }
interface Box { scale: number; }
const box: Box = { height: 5, width: 6, scale: 10 };

// Function member overloads — later interface members have higher priority
interface Cloner { clone(animal: Animal): Animal; }
interface Cloner { clone(animal: Sheep): Sheep; }
// Merged: Sheep overload first, then Animal

// Namespace merging
namespace Animals { export class Zebra {} }
namespace Animals { export class Dog {} }
// Both Zebra and Dog are available on Animals

// Namespace + class
class Album { label: Album.AlbumLabel; }
namespace Album { export class AlbumLabel {} }

// Namespace + function (adds properties to a function)
function buildLabel(name: string): string {
  return buildLabel.prefix + name + buildLabel.suffix;
}
namespace buildLabel {
  export let suffix = "";
  export let prefix = "Hello, ";
}

// Namespace + enum (adds methods to an enum)
enum Color { red = 1, green = 2, blue = 4 }
namespace Color {
  export function mixColor(colorName: string) {
    if (colorName === "yellow") return Color.red + Color.green;
  }
}

// Module augmentation — add to an existing module
// In map.ts:
// import { Observable } from "./observable";
// declare module "./observable" {
//   interface Observable<T> {
//     map<U>(f: (x: T) => U): Observable<U>;
//   }
// }

// Global augmentation from a module file
declare global {
  interface Array<T> {
    toObservable(): Observable<T>;
  }
}
```

Key limitations: cannot create new top-level declarations in module augmentation; classes cannot merge with other classes (use mixins instead).

## Enums

- Reference material for [Enums](https://www.typescriptlang.org/docs/handbook/enums.html)

Enums define a set of named constants. TypeScript supports numeric, string, and heterogeneous enums.

```ts
// Numeric enums — auto-incremented from 0 (or a custom start)
enum Direction { Up, Down, Left, Right }     // 0, 1, 2, 3
enum Direction { Up = 1, Down, Left, Right } // 1, 2, 3, 4

// Numeric enums support reverse mapping
enum Color { Red = 1 }
Color[1];   // "Red"
Color.Red;  // 1

// String enums — no reverse mapping, more debuggable
enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT",
}

// Heterogeneous enums (not recommended)
enum BooleanLike { No = 0, Yes = "YES" }

// Computed and constant members
enum FileAccess {
  None,
  Read    = 1 << 1,
  Write   = 1 << 2,
  ReadWrite = Read | Write,
  G = "123".length, // computed
}

// const enums — fully inlined at compile time, no runtime object
const enum Direction2 { Up, Down, Left, Right }
let dir = Direction2.Up; // compiles to: let dir = 0;

// Ambient enums — describe existing enum shapes
declare enum Enum { A = 1, B, C = 2 }

// Alternative: as const objects (recommended for new code)
const Dir = { Up: "UP", Down: "DOWN" } as const;
type Dir = typeof Dir[keyof typeof Dir]; // "UP" | "DOWN"
```

| Feature | Numeric | String | `const` | Ambient |
|---|---|---|---|---|
| Reverse mapping | Yes | No | No | No |
| Runtime object | Yes | Yes | No | No |
| Computed members | Yes | No | No | Yes |
| Inlined at compile | No | No | Yes | N/A |

## Iterators and Generators

- Reference material for [Iterators and Generators](https://www.typescriptlang.org/docs/handbook/iterators-and-generators.html)

```ts
// Core interfaces
interface Iterator<T, TReturn = any, TNext = undefined> {
  next(...args: [] | [TNext]): IteratorResult<T, TReturn>;
  return?(value?: TReturn): IteratorResult<T, TReturn>;
  throw?(e?: any): IteratorResult<T, TReturn>;
}

interface Iterable<T> {
  [Symbol.iterator](): Iterator<T>;
}

// IterableIterator combines both — most useful in practice
interface IterableIterator<T> extends Iterator<T> {
  [Symbol.iterator](): IterableIterator<T>;
}

// for...of vs for...in
let list = [4, 5, 6];
for (let i in list)  { console.log(i); } // "0", "1", "2" (keys)
for (let i of list)  { console.log(i); } // 4, 5, 6     (values)

// Generator function — yield pauses execution
function* infiniteSequence(): IterableIterator<number> {
  let i = 0;
  while (true) { yield i++; }
}

function* range(start: number, end: number): IterableIterator<number> {
  for (let i = start; i < end; i++) { yield i; }
}

for (const num of range(1, 5)) { console.log(num); } // 1, 2, 3, 4

// Custom iterable class
class Range implements Iterable<number> {
  constructor(private start: number, private end: number) {}

  [Symbol.iterator](): Iterator<number> {
    let current = this.start;
    const end = this.end;
    return {
      next(): IteratorResult<number> {
        if (current <= end) return { value: current++, done: false };
        return { value: undefined as any, done: true };
      }
    };
  }
}
```

For older compile targets, enable full iterator support:
```ts
// tsconfig.json
// { "compilerOptions": { "target": "ES5", "downlevelIteration": true } }
```

## JSX

- Reference material for [JSX](https://www.typescriptlang.org/docs/handbook/jsx.html)

TypeScript supports JSX syntax for projects that use JSX-based libraries. To use JSX: name files `.tsx` and set the `jsx` compiler option.

```ts
// tsconfig.json
// { "compilerOptions": { "jsx": "preserve" } }  // or "react-jsx", etc.
```

JSX emission modes:

| Mode | Input | Output | File Extension |
|------|-------|--------|----------------|
| `preserve` | `<div />` | `<div />` | `.jsx` |
| `react` | `<div />` | `React.createElement("div")` | `.js` |
| `react-jsx` | `<div />` | `_jsx("div", {})` | `.js` |

```tsx
// Intrinsic elements — lowercase, mapped via JSX.IntrinsicElements
const element = <div className="box" />;

// Value-based elements — capitalized components
function MyButton(props: { label: string }) {
  return <button>{props.label}</button>;
}
const btn = <MyButton label="Click me" />;

// Props type checking
interface ButtonProps {
  label: string;
  onClick: () => void;
  disabled?: boolean;
}
function Button({ label, onClick, disabled }: ButtonProps) {
  return <button onClick={onClick} disabled={disabled}>{label}</button>;
}

// Generic components
function Identity<T>(props: { value: T; render: (val: T) => JSX.Element }) {
  return props.render(props.value);
}
```

Key compiler options: `jsx`, `jsxFactory`, `jsxFragmentFactory`, `jsxImportSource`.

## Mixins

- Reference material for [Mixins](https://www.typescriptlang.org/docs/handbook/mixins.html)

Mixins compose classes from reusable parts since TypeScript does not support multiple inheritance directly. A mixin is a function that takes a base class and returns a new extended class.

```ts
// Base constructor type
type Constructor<T = {}> = new (...args: any[]) => T;

// Timestamped mixin
function Timestamped<TBase extends Constructor>(Base: TBase) {
  return class extends Base {
    timestamp = Date.now();
  };
}

// Activatable mixin
function Activatable<TBase extends Constructor>(Base: TBase) {
  return class extends Base {
    isActive = false;
    activate()   { this.isActive = true; }
    deactivate() { this.isActive = false; }
  };
}

class User { name = ""; }

// Compose multiple mixins
const TimestampedUser = Timestamped(User);
const TimestampedActivatableUser = Timestamped(Activatable(User));

const u = new TimestampedActivatableUser();
u.activate();
console.log(u.isActive, u.timestamp);

// Constrained mixin — requires base to have specific shape
type Spritable = Constructor<{ speed: number }>;

function Jumpable<TBase extends Spritable>(Base: TBase) {
  return class extends Base {
    jump() { console.log(`Jumping at speed ${this.speed}`); }
  };
}
```

| Rule | Detail |
|------|--------|
| Mixin is a function | Takes a class, returns a new class |
| Type constraint | Use `Constructor<T>` to require specific base shape |
| Composition order | Applied right-to-left: `A(B(C))` |
| Constructors | Must call `super(...args)` in mixin constructors |

## Namespaces

- Reference material for [Namespaces](https://www.typescriptlang.org/docs/handbook/namespaces.html)

Namespaces (formerly "internal modules") organize code into named scopes to prevent global naming collisions. Only items marked `export` are accessible outside the namespace.

```ts
// Basic namespace
namespace Validation {
  export interface StringValidator {
    isAcceptable(s: string): boolean;
  }

  const lettersRegexp = /^[A-Za-z]+$/; // private

  export class LettersOnlyValidator implements StringValidator {
    isAcceptable(s: string) { return lettersRegexp.test(s); }
  }
}

const validator = new Validation.LettersOnlyValidator();

// Multi-file namespaces — use reference tags
// /// <reference path="Validation.ts" />
// namespace Validation { ... }

// Compile with: tsc --outFile sample.js Validation.ts LettersValidator.ts

// Namespace alias — shorthand for deep nesting
namespace Shapes {
  export namespace Polygons {
    export class Triangle {}
    export class Square {}
  }
}
import polygons = Shapes.Polygons;
let sq = new polygons.Square();

// Ambient namespace — for external JS libraries without types
declare namespace D3 {
  export interface Selectors {
    select(selector: string): Selection;
  }
  export interface Selection {
    attr(name: string, value: string): Selection;
  }
}
```

Note: for new projects, prefer ES modules (`import`/`export`) over namespaces.

## Namespaces and Modules

- Reference material for [Namespaces and Modules](https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html)

Modules (ES modules) are the modern, standard approach for organizing TypeScript code. Namespaces are a legacy mechanism primarily useful for ambient declarations and declaration files.

```ts
// Modules — file-based, isolated scope
// math.ts
export function add(a: number, b: number): number { return a + b; }

// app.ts
import { add } from "./math";
console.log(add(1, 2));

// Namespace — global scope by default
namespace Validation {
  export class LettersOnlyValidator { /* ... */ }
}

// Anti-pattern: wrapping module exports in a namespace
export namespace Utils {
  export function helper() {} // callers need Utils.helper() — unnecessary nesting
}

// Better: export directly
export function helper() {}
```

Pitfalls of using namespaces in module files:

| Pitfall | Description |
|---|---|
| Namespace over modules | Redundant and confusing in a module system |
| Global pollution | Namespaces live on the global scope by default |
| No tree-shaking | Bundlers cannot eliminate unused namespace code |
| `/// <reference>` complexity | Multi-file namespaces require manual dependency ordering |
| Deep nesting | `App.Utils.Strings.trim` becomes unwieldy |

When to use modules vs namespaces:
- **Modules**: all new applications and libraries, any code using a bundler or Node.js
- **Namespaces**: `.d.ts` declaration files for global scripts, legacy non-module scripts, UMD global library typings

## Symbols

- Reference material for [Symbols](https://www.typescriptlang.org/docs/handbook/symbols.html)

`symbol` is a primitive type (ES2015+). Each `Symbol()` produces a unique, immutable value.

```ts
// Symbol creation — always unique
const sym1 = Symbol();
const sym2 = Symbol("description");
const sym3 = Symbol("description");
sym2 === sym3; // false

// unique symbol — compile-time unique identity, must be const
const KEY: unique symbol = Symbol("key");

// Symbols as object keys — not enumerable in for...in or Object.keys()
const id = Symbol("id");
const user = { name: "Alice", [id]: 42 };
console.log(user[id]); // 42

// Global symbol registry — shared across realms
const s1 = Symbol.for("shared");
const s2 = Symbol.for("shared");
s1 === s2;           // true
Symbol.keyFor(s1);   // "shared"

// Well-known symbols customize language behavior
class Range {
  constructor(public start: number, public end: number) {}

  [Symbol.iterator]() {
    let current = this.start;
    const end = this.end;
    return {
      next(): IteratorResult<number> {
        return current <= end
          ? { value: current++, done: false }
          : { value: undefined as any, done: true };
      }
    };
  }
}

// Symbol.toPrimitive — custom type coercion
class Temperature {
  constructor(private celsius: number) {}
  [Symbol.toPrimitive](hint: string) {
    if (hint === "number") return this.celsius;
    if (hint === "string") return `${this.celsius}°C`;
    return this.celsius;
  }
}

// Symbol.hasInstance — custom instanceof behavior
class EvenNumber {
  static [Symbol.hasInstance](value: unknown): boolean {
    return typeof value === "number" && value % 2 === 0;
  }
}
4 instanceof EvenNumber; // true
5 instanceof EvenNumber; // false
```

Well-known symbols:

| Symbol | Purpose |
|---|---|
| `Symbol.iterator` | Custom iteration (`for...of`) |
| `Symbol.asyncIterator` | Async iteration |
| `Symbol.hasInstance` | `instanceof` behavior |
| `Symbol.toPrimitive` | Type coercion |
| `Symbol.toStringTag` | `Object.prototype.toString` tag |
| `Symbol.species` | Constructor for derived objects |

## Triple-Slash Directives

- Reference material for [Triple-Slash Directives](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html)

Triple-slash directives are single-line XML-tag comments that must appear at the top of a file before any code. They serve as compiler instructions. Directives are ignored inside module files (files that contain `import`/`export`).

```ts
// /// <reference path="..." /> — declares dependency on another file
/// <reference path="./utils.ts" />
/// <reference path="../typings/jquery.d.ts" />

// /// <reference types="..." /> — declares dependency on a @types package
/// <reference types="node" />
/// <reference types="jest" />

// /// <reference lib="..." /> — includes a specific built-in lib
/// <reference lib="es2017.string" />
/// <reference lib="dom" />
/// <reference lib="es2015.iterable" />

function toArray<T>(iter: Iterable<T>): T[] { return [...iter]; }

// /// <reference no-default-lib="true" /> — marks file as a library,
// prevents compiler from including default lib.d.ts files
// Found in TypeScript's own built-in lib files; rarely used in user code.

// /// <amd-module name="..." /> — assigns a name to an AMD module
/// <amd-module name="NamedModule" />
export class C {}
// Compiled AMD output: define("NamedModule", ["require", "exports"], ...)

// /// <amd-dependency path="..." /> — deprecated; use import instead
```

Key rules:

| Rule | Detail |
|------|--------|
| Placement | Must appear before any code, imports, or non-directive comments |
| Modules | Directives are ignored inside ES module files |
| `noResolve` | With `--noResolve` flag, `reference path` directives are ignored |

Common use in published `.d.ts` files:
```ts
// mylib.d.ts
/// <reference types="node" />
export declare function readConfig(path: string): NodeJS.ProcessEnv;
```

## Type Compatibility

- Reference material for [Type Compatibility](https://www.typescriptlang.org/docs/handbook/type-compatibility.html)

TypeScript uses structural typing (duck typing) — types are compatible if their shapes match, regardless of how they were declared.

```ts
// Structural typing — shape matters, not declaration
interface Named { name: string; }
class Person { name: string = ""; }

let p: Named = new Person(); // OK — Person has the required shape

// Object compatibility — target needs at least the source's properties
interface Pet { name: string; }
interface Dog { name: string; breed: string; }
let pet: Pet;
let dog: Dog = { name: "Rex", breed: "Lab" };
pet = dog;  // OK — Dog has everything Pet needs
// dog = pet; // Error — Pet lacks `breed`

// Function compatibility — fewer parameters is OK
let handler: (a: number, b: number) => void;
handler = (a: number) => {}; // OK — extra params are ignored

// Return types — source return type must be a subtype of target
class Animal { feet: number = 4; }
class DogAnimal extends Animal { name: string = ""; }
let getAnimal: () => Animal;
let getDog: () => DogAnimal = () => new DogAnimal();
getAnimal = getDog; // OK — DogAnimal is a subtype of Animal

// Generics — compared after substitution
interface Empty<T> {}
let x: Empty<number>;
let y: Empty<string>;
x = y; // OK — identical structure regardless of T

interface NotEmpty<T> { data: T; }
let a: NotEmpty<number>;
let b: NotEmpty<string>;
// a = b; // Error — number !== string

// Enum compatibility — different enums are incompatible with each other
enum Status { Active, Inactive }
enum Color  { Red, Green }
// let s: Status = Color.Red; // Error

let n: number = Status.Active; // OK — numeric enums are compatible with number

// Class compatibility — only instance members compared (statics ignored)
class A { feet = 4; }
class B { feet = 4; name = ""; }
let ca: A = new B(); // OK

// Private members must come from the same declaration
class X { private secret = 1; }
class Z { private secret = 1; }
// let cx: X = new Z(); // Error — different private declarations
```

Assignment compatibility extends subtype compatibility: `any` is assignable to/from anything; `void` is interchangeable with `undefined` in assignments.

## Type Inference

- Reference material for [Type Inference](https://www.typescriptlang.org/docs/handbook/type-inference.html)

TypeScript infers types automatically when no explicit annotation is given.

```ts
// Basic inference from initializers
let x = 3;           // number
let name = "Alice";  // string
let flag = true;     // boolean

// Best common type — union of candidate types
let arr = [0, 1, null];
// inferred as: (number | null)[]

class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

let animals = [new Dog(), new Cat()];
// inferred as: (Dog | Cat)[]
// NOT Animal[] — Animal must be explicitly included:
let animals2: Animal[] = [new Dog(), new Cat()];

// Contextual typing — type flows in from context
window.onmousedown = function(mouseEvent) {
  console.log(mouseEvent.button);   // OK — inferred as MouseEvent
  // console.log(mouseEvent.kangaroo); // Error
};

const names = ["Alice", "Bob"];
names.forEach(function(name) {
  console.log(name.toUpperCase()); // name inferred as string
});

// Return type inference
function add(x: number, y: number) {
  return x + y; // return type: number
}

function getValue(flag: boolean) {
  if (flag) return 42;
  return "default";
  // return type: number | string
}
```

| Concept | Behavior |
|---|---|
| Basic inference | Type flows from initializer/value |
| Best common type | Union of candidate types |
| Contextual typing | Type flows from usage context |
| Return type inference | Derived from all `return` paths |

## Variable Declaration

- Reference material for [Variable Declaration](https://www.typescriptlang.org/docs/handbook/variable-declarations.html)

```ts
// var — function-scoped, hoisted, allows re-declaration (avoid)
var x = 10;
for (var i = 0; i < 10; i++) {
  setTimeout(() => console.log(i), 100); // prints 10, ten times (closure over same i)
}

// let — block-scoped, temporal dead zone, no re-declaration
let y = 10;
if (true) {
  let y = 20; // different y — block-scoped
}
for (let i = 0; i < 10; i++) {
  setTimeout(() => console.log(i), 100); // prints 0–9 correctly
}

// const — block-scoped, immutable binding (object content still mutable)
const PI = 3.14;
// PI = 3; // Error
const obj = { name: "Alice" };
obj.name = "Bob"; // OK — content is mutable
// obj = {};     // Error — binding is immutable

// Array destructuring
let [first, second] = [1, 2];
let [, , third] = [1, 2, 3];             // skip elements
let [head, ...tail] = [1, 2, 3, 4];      // rest: tail = [2, 3, 4]
let [a = 0, b = 1] = [5];               // defaults: a=5, b=1
[first, second] = [second, first];       // swap

// Object destructuring
let { name, age } = { name: "Alice", age: 30 };
let { name: userName } = { name: "Alice" }; // rename
let { p = 5, q = 10 } = { p: 3 };          // defaults
let { x, ...rest } = { x: 1, y: 2, z: 3 }; // rest properties

// Function parameter destructuring
function greet({ name, age = 0 }: { name: string; age?: number }) {
  console.log(`${name} is ${age}`);
}

// Spread operator
let arr1 = [1, 2];
let arr2 = [3, 4];
let combined = [...arr1, ...arr2]; // [1, 2, 3, 4]

let obj1 = { a: 1, b: 2 };
let obj2 = { b: 3, c: 4 };
let merged = { ...obj1, ...obj2 }; // { a: 1, b: 3, c: 4 } — later props overwrite
```

Scoping rules:

| Feature | Scope | Hoisted | Re-declarable | Re-assignable |
|---|---|---|---|---|
| `var` | Function/Global | Yes | Yes | Yes |
| `let` | Block | No (TDZ) | No | Yes |
| `const` | Block | No (TDZ) | No | No |

Best practice: prefer `const` by default, use `let` when reassignment is needed, avoid `var`.


path: references/keywords.md
content: # TypeScript Keywords

## TypeScript Keyof

- Reference material for [Keyof](https://www.w3schools.com/typescript/typescript_keyof.php)
- See [Keyof Type Operator](https://www.typescriptlang.org/docs/handbook/2/keyof-types.html) for additional information
- See [Typeof Type Operator](https://www.typescriptlang.org/docs/handbook/2/typeof-types.html) for additional information

### Parameters

```ts
interface Person {
  name: string;
  age: number;
}
// `keyof Person` here creates a union type of "name" and "age",
// other strings will not be allowed
function printPersonProperty(person: Person, property: keyof Person) {
  console.log(`Printing person property ${property}: "${person[property]}"`);
}
let person = {
  name: "Max",
  age: 27
};
printPersonProperty(person, "name"); // Printing person property name: "Max"
```

```ts
type StringMap = { [key: string]: unknown };
// `keyof StringMap` resolves to `string` here
function createStringPair(property: keyof StringMap, value: string): StringMap {
  return { [property]: value };
}
```

## TypeScript Null & Undefined

- Reference material for [Null & Undefined](https://www.w3schools.com/typescript/typescript_null.php)
- See [Everyday Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html) for additional information
- See [Narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html) for additional information

### Types

```ts
let value: string | undefined | null = null;
value = 'hello';
value = undefined;
```

### Optional Chaining

```ts
interface House {
  sqft: number;
  yard?: {
    sqft: number;
  };
}
function printYardSize(house: House) {
  const yardSize = house.yard?.sqft;
  if (yardSize === undefined) {
    console.log('No yard');
  } else {
    console.log(`Yard is ${yardSize} sqft`);
  }
}

let home: House = {
  sqft: 500
};

printYardSize(home); // Prints 'No yard'
```

### Nullish Coalescing

```ts
function printMileage(mileage: number | null | undefined) {
  console.log(`Mileage: ${mileage ?? 'Not Available'}`);
}

printMileage(null); // Prints 'Mileage: Not Available'
printMileage(0); // Prints 'Mileage: 0'
```

### Null Assertion

```ts
function getValue(): string | undefined {
  return 'hello';
}
let value = getValue();
console.log('value length: ' + value!.length);
```

```ts
let array: number[] = [1, 2, 3];
let value = array[0];
// with `noUncheckedIndexedAccess` this has the type `number | undefined`
```

## TypeScript Definitely Typed

- Reference material for [Definitely Typed](https://www.w3schools.com/typescript/typescript_definitely_typed.php)
- See [Declaration Files Introduction](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html) for additional information

### Installation

```bash
npm install --save-dev @types/jquery
```

## TypeScript 5.x Update

- Reference material for [5.x Update](https://www.w3schools.com/typescript/typescript_5_updates.php)
- See [Template Literal Types](https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html) for additional information

### Template Literal Types

```ts
type Color = "red" | "green" | "blue";
type HexColor<T extends Color> = `#${string}`;

// Usage:
let myColor: HexColor<"blue"> = "#0000FF";
```

### Index Signature Labels

```ts
type DynamicObject = { [key: `dynamic_${string}`]: string };

// Usage:
let obj: DynamicObject = { dynamic_key: "value" };
```


path: references/miscellaneous.md
content: # TypeScript Miscellaneous

## TypeScript Async Programming

- Reference material for [Async Programming](https://www.w3schools.com/typescript/typescript_async.php)
- See [Iterators and Generators](https://www.typescriptlang.org/docs/handbook/iterators-and-generators.html) for additional information
- See [Symbols](https://www.typescriptlang.org/docs/handbook/symbols.html) for additional information

### Promises in TypeScript

```ts
// Create a typed Promise that resolves to a string
const fetchGreeting = (): Promise<string> => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = Math.random() > 0.5;
      if (success) {
        resolve("Hello, TypeScript!");
      } else {
        reject(new Error("Failed to fetch greeting"));
      }
    }, 1000);
  });
};

// Using the Promise with proper type inference
fetchGreeting()
  .then((greeting) => {
    // TypeScript knows 'greeting' is a string
    console.log(greeting.toUpperCase());
  })
  .catch((error: Error) => {
    console.error("Error:", error.message);
  });
```

### Async/Await with TypeScript

```ts
// Define types for our API response
interface User {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user' | 'guest';
}

// Function that returns a Promise of User array
async function fetchUsers(): Promise<User[]> {
  console.log('Fetching users...');
  // Simulate API call
  await new Promise(resolve => setTimeout(resolve, 1000));
  return [
    { id: 1, name: 'Alice', email: '[REDACTED_SECRET]', role: 'admin' },
    { id: 2, name: 'Bob', email: '[REDACTED_SECRET]', role: 'user' }
  ];
}

// Async function to process users
async function processUsers() {
  try {
    // TypeScript knows users is User[]
    const users = await fetchUsers();
    console.log(`Fetched ${users.length} users`);

    // Type-safe property access
    const adminEmails = users
      .filter(user => user.role === 'admin')
      .map(user => user.email);

    console.log('Admin emails:', adminEmails);
    return users;
  } catch (error) {
    if (error instanceof Error) {
      console.error('Failed to process users:', error.message);
    } else {
      console.error('An unknown error occurred');
    }
    throw error; // Re-throw to let caller handle
  }
}

// Execute the async function
processUsers()
  .then(users => console.log('Processing complete'))
  .catch(err => console.error('Processing failed:', err));
```

### Run multiple async operations in parallel

```ts
interface Product {
  id: number;
  name: string;
  price: number;
}

async function fetchProduct(id: number): Promise<Product> {
  console.log(`Fetching product ${id}...`);
  await new Promise(resolve => setTimeout(resolve, Math.random() * 1000));
  return { id, name: `Product ${id}`, price: Math.floor(Math.random() * 100) };
}

async function fetchMultipleProducts() {
  try {
    // Start all fetches in parallel
    const [product1, product2, product3] = await Promise.all([
      fetchProduct(1),
      fetchProduct(2),
      fetchProduct(3)
    ]);

    const total = [product1, product2, product3]
      .reduce((sum, product) => sum + product.price, 0);
    console.log(`Total price: $${total.toFixed(2)}`);
  } catch (error) {
    console.error('Error fetching products:', error);
  }
}

fetchMultipleProducts();
```

### Typing Callbacks for Async Operations

```ts
// Define a type for the callback
type FetchCallback = (error: Error | null, data?: string) => void;

// Function that takes a typed callback
function fetchDataWithCallback(url: string, callback: FetchCallback): void {
  // Simulate async operation
  setTimeout(() => {
    try {
      // Simulate successful response
      callback(null, "Response data");
    } catch (error) {
      callback(error instanceof Error ? error : new Error('Unknown error'));
    }
  }, 1000);
}

// Using the callback function
fetchDataWithCallback('https://api.example.com', (error, data) => {
  if (error) {
    console.error('Error:', error.message);
    return;
  }

  // TypeScript knows data is a string (or undefined)
  if (data) {
    console.log(data.toUpperCase());
  }
});
```

### Promise.all - Run multiple promises in parallel

```ts
// Different types of promises
const fetchUser = (id: number): Promise<{ id: number; name: string }> =>
  Promise.resolve({ id, name: `User ${id}` });

const fetchPosts = (userId: number): Promise<Array<{ id: number; title: string }>> =>
  Promise.resolve([
    { id: 1, title: 'Post 1' },
    { id: 2, title: 'Post 2' }
  ]);

const fetchStats = (userId: number): Promise<{ views: number; likes: number }> =>
  Promise.resolve({ views: 100, likes: 25 });

// Run all in parallel
async function loadUserDashboard(userId: number) {
  try {
    const [user, posts, stats] = await Promise.all([
      fetchUser(userId),
      fetchPosts(userId),
      fetchStats(userId)
    ]);

    // TypeScript knows the types of user, posts, and stats
    console.log(`User: ${user.name}`);
    console.log(`Posts: ${posts.length}`);
    console.log(`Likes: ${stats.likes}`);

    return { user, posts, stats };
  } catch (error) {
    console.error('Failed to load dashboard:', error);
    throw error;
  }
}

// Execute with a user ID
loadUserDashboard(1);
```

### Promise.race - Useful for timeouts

```ts
// Helper function for timeout
const timeout = (ms: number): Promise<never> =>
  new Promise((_, reject) =>
    setTimeout(() => reject(new Error(`Timeout after ${ms}ms`)), ms)
  );

// Simulate API call with timeout
async function fetchWithTimeout<T>(
  promise: Promise<T>,
  timeoutMs: number = 5000
): Promise<T> {
  return Promise.race([
    promise,
    timeout(timeoutMs).then(() => {
      throw new Error(`Request timed out after ${timeoutMs}ms`);
    }),
  ]);
}

// Usage example
async function fetchUserData() {
  try {
    const response = await fetchWithTimeout(
      fetch('https://api.example.com/user/1'),
      3000 // 3 second timeout
    );
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Error:', (error as Error).message);
    throw error;
  }
}
```

### Promise.allSettled - Wait for all promises regardless of outcome

```ts
// Simulate multiple API calls with different outcomes
const fetchData = async (id: number) => {
  // Randomly fail some requests
  if (Math.random() > 0.7) {
    throw new Error(`Failed to fetch data for ID ${id}`);
  }
  return { id, data: `Data for ${id}` };
};

// Process multiple items with individual error handling
async function processBatch(ids: number[]) {
  const promises = ids.map(id =>
    fetchData(id)
      .then(value => ({ status: 'fulfilled' as const, value }))
      .catch(reason => ({ status: 'rejected' as const, reason }))
  );

  // Wait for all to complete
  const results = await Promise.allSettled(promises);

  // Process results
  const successful = results
    .filter((result): result is PromiseFulfilledResult<{
     status: 'fulfilled', value: any }> =>
      result.status === 'fulfilled' &&
      result.value.status === 'fulfilled'
    )
    .map(r => r.value.value);

  const failed = results
    .filter((result): result is PromiseRejectedResult |
      PromiseFulfilledResult<{ status: 'rejected', reason: any }> => {
      if (result.status === 'rejected') return true;
      return result.value.status === 'rejected';
    });

  console.log(`Successfully processed: ${successful.length}`);
  console.log(`Failed: ${failed.length}`);

  return { successful, failed };
}

// Process a batch of IDs
processBatch([1, 2, 3, 4, 5]);
```

### Custom Error Classes for Async Operations

```ts
// Base error class for our application
class AppError extends Error {
  constructor(
    message: string,
    public readonly code: string,
    public readonly details?: unknown
  ) {
    super(message);
    this.name = this.constructor.name;
    Error.captureStackTrace?.(this, this.constructor);
  }
}

// Specific error types
class NetworkError extends AppError {
  constructor(message: string, details?: unknown) {
    super(message, 'NETWORK_ERROR', details);
  }
}

class ValidationError extends AppError {
  constructor(
    public readonly field: string,
    message: string
  ) {
    super(message, 'VALIDATION_ERROR', { field });
  }
}

class NotFoundError extends AppError {
  constructor(resource: string, id: string | number) {
    super(
      `${resource} with ID ${id} not found`,
      'NOT_FOUND',
      { resource, id }
    );
  }
}

// Usage example
async function fetchUserData(userId: string):
Promise<{ id: string; name: string }> {
  try {
    // Simulate API call
    const response = await fetch(`/api/users/${userId}`);

    if (!response.ok) {
      if (response.status === 404) {
        throw new NotFoundError('User', userId);
       } else if (response.status >= 500) {
        throw new NetworkError('Server error', { status: response.status });
       } else {
        throw new Error(`HTTP error! status: ${response.status}`);
       }
    }

    const data = await response.json();

    // Validate response data
    if (!data.name) {
      throw new ValidationError('name', 'Name is required');
    }

    return data;
  } catch (error) {
    if (error instanceof AppError) {
      // Already one of our custom errors
      throw error;
    }
    // Wrap unexpected errors
    throw new AppError(
      'Failed to fetch user data',
      'UNEXPECTED_ERROR',
      { cause: error }
    );
  }
}

// Error handling in the application
async function displayUserProfile(userId: string) {
  try {
    const user = await fetchUserData(userId);
    console.log('User profile:', user);
  } catch (error) {
    if (error instanceof NetworkError) {
      console.error('Network issue:', error.message);
      // Show retry UI
    } else if (error instanceof ValidationError) {
      console.error('Validation failed:', error.message);
      // Highlight the invalid field
    } else if (error instanceof NotFoundError) {
      console.error('Not found:', error.message);
      // Show 404 page
    } else {
      console.error('Unexpected error:', error);
      // Show generic error message
    }
  }
}

// Execute with example data
displayUserProfile('123');
```

### Async Generators

```ts
// Async generator function
async function* generateNumbers(): AsyncGenerator<number, void, unknown> {
  let i = 0;
  while (i < 5) {
    // Simulate async operation
    await new Promise(resolve => setTimeout(resolve, 1000));
    yield i++;
  }
}

// Using the async generator
async function consumeNumbers() {
  for await (const num of generateNumbers()) {
    // TypeScript knows num is a number
    console.log(num * 2);
  }
}
```

## TypeScript Decorators

- Reference material for [Decorators](https://www.w3schools.com/typescript/typescript_decorators.php)
- See [Decorators](https://www.typescriptlang.org/docs/handbook/decorators.html) for additional information
- See [Declaration Merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html) for additional information

### Enabling Decorators

```json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "strictPropertyInitialization": false
  },
  "include": ["src/**/*.ts"]
}
```

### Class Decorators

```ts
// A simple class decorator that logs class definition
function logClass(constructor: Function) {
  console.log(`Class ${constructor.name} was defined at ${new Date().toISOString()}`);
}

// Applying the decorator
@logClass
class UserService {
  getUsers() {
    return ['Alice', 'Bob', 'Charlie'];
  }
}

// Output when the file is loaded: "Class UserService was defined at [timestamp]"
```

### Class Decorators - Adding Properties and Methods

```ts
// A decorator that adds a version property and logs instantiation
function versioned(version: string) {
  return function (constructor: Function) {
    // Add a static property
    constructor.prototype.version = version;

    // Store the original constructor
    const original = constructor;
    // Create a new constructor that wraps the original
    const newConstructor: any = function (...args: any[]) {
      console.log(`Creating instance of ${original.name} v${version}`);
      return new original(...args);
    };

    // Copy prototype so instanceof works
    newConstructor.prototype = original.prototype;
    return newConstructor;
  };
}

// Applying the decorator with a version
@versioned('1.0.0')
class ApiClient {
  fetchData() {
    console.log('Fetching data...');
  }
}

const client = new ApiClient();
console.log((client as any).version); // Outputs: 1.0.0
client.fetchData();
```

### Class Decorators - Sealed Classes

```ts
function sealed(constructor: Function) {
  console.log(`Sealing ${constructor.name}...`);
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

@sealed
class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet() {
    return `Hello, ${this.greeting}`;
  }
}

// This will throw an error in strict mode
// Greeter.prototype.newMethod = function() {};
// Error: Cannot add property newMethod
```

### Method Decorators - Measure Execution Time

```ts
// Method decorator to measure execution time
function measureTime(
 target: any,
 propertyKey: string,
 descriptor: PropertyDescriptor
) {
  const originalMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    const start = performance.now();
    const result = originalMethod.apply(this, args);
    const end = performance.now();
    console.log(`${propertyKey} executed in ${(end - start).toFixed(2)}ms`);
    return result;
  };
  return descriptor;
}

// Using the decorator
class DataProcessor {
  @measureTime
  processData(data: number[]): number[] {
    // Simulate processing time
    for (let i = 0; i < 100000000; i++) {
      /* processing */
    }
    return data.map(x => x * 2);
  }
}

// When called, it will log the execution time
const processor = new DataProcessor();
processor.processData([1, 2, 3, 4, 5]);
```

### Method Decorators - Role-Based Access Control

```ts
// User roles
type UserRole = 'admin' | 'editor' | 'viewer';

// Current user context (simplified)
const currentUser = {
  id: 1,
  name: 'John Doe',
  roles: ['viewer'] as UserRole[]
};

// Decorator factory for role-based access control
function AllowedRoles(...allowedRoles: UserRole[]) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
      const hasPermission = allowedRoles.some(role =>
        currentUser.roles.includes(role)
      );
      if (!hasPermission) {
        throw new Error(
          `User ${currentUser.name} is not authorized to call ${propertyKey}`
        );
      }
      return originalMethod.apply(this, args);
    };
    return descriptor;
  };
}

// Using the decorator
class DocumentService {
  @AllowedRoles('admin', 'editor')
  deleteDocument(id: string) {
    console.log(`Document ${id} deleted`);
  }

  @AllowedRoles('admin', 'editor', 'viewer')
  viewDocument(id: string) {
    console.log(`Viewing document ${id}`);
  }
}

// Usage
const docService = new DocumentService();
try {
  docService.viewDocument('doc123'); // Works - viewer role is allowed
  docService.deleteDocument('doc123'); // Throws error - viewer cannot delete
} catch (error) {
  console.error(error.message);
}

// Change user role to admin
currentUser.roles = ['admin'];
docService.deleteDocument('doc123'); // Now works - admin can delete
```

### Method Decorators - Deprecation Warning

```ts
function deprecated(message: string) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
      console.warn(`Warning: ${propertyKey} is deprecated. ${message}`);
      return originalMethod.apply(this, args);
    };
    return descriptor;
  };
}

class PaymentService {
  @deprecated('Use processPaymentV2 instead')
  processPayment(amount: number, currency: string) {
    console.log(`Processing payment of ${amount} ${currency}`);
  }

  processPaymentV2(amount: number, currency: string) {
    console.log(`Processing payment v2 of ${amount} ${currency}`);
  }
}

const payment = new PaymentService();
payment.processPayment(100, 'USD'); // Shows deprecation warning
payment.processPaymentV2(100, 'USD'); // No warning
```

### Property Decorators - Format Properties

```ts
// Property decorator to format a string property
function format(formatString: string) {
  return function (target: any, propertyKey: string) {
    let value: string;
    const getter = () => value;
    const setter = (newVal: string) => {
      value = formatString.replace('{}', newVal);
    };
    Object.defineProperty(target, propertyKey, {
      get: getter,
      set: setter,
      enumerable: true,
      configurable: true
    });
  };
}

class Greeter {
  @format('Hello, {}!')
  greeting: string;
}

const greeter = new Greeter();
greeter.greeting = 'World';
console.log(greeter.greeting); // Outputs: Hello, World!
```

### Property Decorators - Log Property Access

```ts
function logProperty(target: any, propertyKey: string) {
  let value: any;
  const getter = function() {
    console.log(`Getting ${propertyKey}: ${value}`);
    return value;
  };

  const setter = function(newVal: any) {
    console.log(`Setting ${propertyKey} from ${value} to ${newVal}`);
    value = newVal;
  };

  Object.defineProperty(target, propertyKey, {
    get: getter,
    set: setter,
    enumerable: true,
    configurable: true
  });
}

class Product {
  @logProperty
  name: string;

  @logProperty
  price: number;

  constructor(name: string, price: number) {
    this.name = name;
    this.price = price;
  }
}

const product = new Product('Laptop', 999.99);
product.price = 899.99; // Logs: Setting price from 999.99 to 899.99
console.log(product.name); // Logs: Getting name: Laptop
```

### Property Decorators - Required Properties

```ts
function required(target: any, propertyKey: string) {
  let value: any;

  const getter = function() {
    if (value === undefined) {
      throw new Error(`Property ${propertyKey} is required`);
    }
    return value;
  };

  const setter = function(newVal: any) {
    value = newVal;
  };

  Object.defineProperty(target, propertyKey, {
    get: getter,
    set: setter,
    enumerable: true,
    configurable: true
  });
}

class User {
  @required
  username: string;

  @required
  email: string;

  age?: number;

  constructor(username: string, email: string) {
    this.username = username;
    this.email = email;
  }
}

const user1 = new User('johndoe', '[REDACTED_SECRET]'); // Works
// const user2 = new User(undefined, '[REDACTED_SECRET]');
// Throws error: Property username is required
```

### Parameter Decorators - Validation

```ts
function validateParam(type: 'string' | 'number' | 'boolean') {
  return function (
    target: any,
    propertyKey: string | symbol,
    parameterIndex: number
  ) {
    const existingValidations: any[] =
      Reflect.getOwnMetadata('validations', target, propertyKey) || [];

    existingValidations.push({ index: parameterIndex, type });
    Reflect.defineMetadata(
      'validations', existingValidations, target, propertyKey
    );
  };
}

function validate(
  target: any,
  propertyKey: string,
  descriptor: PropertyDescriptor
) {
  const originalMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    const validations: Array<{index: number, type: string}> =
      Reflect.getOwnMetadata('validations', target, propertyKey) || [];

    for (const validation of validations) {
      const { index, type } = validation;
      const param = args[index];
      let isValid = false;

      switch (type) {
        case 'string':
          isValid = typeof param === 'string' && param.length > 0;
          break;
        case 'number':
          isValid = typeof param === 'number' && !isNaN(param);
          break;
        case 'boolean':
          isValid = typeof param === 'boolean';
      }

      if (!isValid) {
        throw new Error(`Parameter at index ${index} failed ${type} validation`);
      }
    }

    return originalMethod.apply(this, args);
  };
  return descriptor;
}

class UserService {
  @validate
  createUser(
    @validateParam('string') name: string,
    @validateParam('number') age: number,
    @validateParam('boolean') isActive: boolean
  ) {
    console.log(`Creating user: ${name}, ${age}, ${isActive}`);
  }
}

const service = new UserService();
service.createUser('John', 30, true); // Works
// service.createUser('', 30, true);
// Throws error: Parameter at index 0 failed string validation
```

### Decorator Factories - Configurable Logging

```ts
// Decorator factory that accepts configuration
function logWithConfig(config: {
  level: 'log' | 'warn' | 'error',
  message?: string
}) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
      const { level = 'log', message = 'Executing method' } = config;

      console[level](`${message}: ${propertyKey}`, { arguments: args });
      const result = originalMethod.apply(this, args);
      console[level](`${propertyKey} completed`);
      return result;
    };
    return descriptor;
  };
}

class PaymentService {
  @logWithConfig({ level: 'log', message: 'Processing payment' })
  processPayment(amount: number) {
    console.log(`Processing payment of $${amount}`);
  }
}
```

### Decorator Evaluation Order

```ts
function first() {
  console.log('first(): factory evaluated');
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log('first(): called');
  };
}

function second() {
  console.log('second(): factory evaluated');
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log('second(): called');
  };
}

class ExampleClass {
  @first()
  @second()
  method() {}
}

// Output:
// second(): factory evaluated
// first(): factory evaluated
// first(): called
// second(): called
```

### Real-World Example - API Controller

```ts
// Simple decorator implementations (simplified for example)
const ROUTES: any[] = [];

function Controller(prefix: string = '') {
  return function (constructor: Function) {
    constructor.prototype.prefix = prefix;
  };
}

function Get(path: string = '') {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    ROUTES.push({
      method: 'get',
      path,
      handler: descriptor.value,
      target: target.constructor
    });
  };
}

// Using the decorators
@Controller('/users')
class UserController {
  @Get('/')
  getAllUsers() {
    return { users: [{ id: 1, name: 'John' }] };
  }

  @Get('/:id')
  getUserById(id: string) {
    return { id, name: 'John' };
  }
}

// Simulate route registration
function registerRoutes() {
  ROUTES.forEach(route => {
    const prefix = route.target.prototype.prefix || '';
    console.log(`Registered ${route.method.toUpperCase()} ${prefix}${route.path}`);
  });
}

registerRoutes();
// Output:
// Registered GET /users
// Registered GET /users/:id
```

### Common Pitfalls

```ts
function readonly(target: any, propertyKey: string) {
  Object.defineProperty(target, propertyKey, {
    writable: false
  });
}

class Person {
  @readonly
  name = "John";
}
```

```ts
function logParameter(target: any, propertyKey: string, parameterIndex: number) {
  console.log(`Parameter in ${propertyKey} at index ${parameterIndex}`);
}

class Demo {
  greet(@logParameter message: string) {
    return message;
  }
}
```

```json
{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}
```

## TypeScript in JavaScript Projects (*JSDoc*)

- Reference material for [JavaScript Projects (*JSDoc*)](https://www.w3schools.com/typescript/typescript_jsdoc.php)
- See [JS Projects Utilizing TypeScript](https://www.typescriptlang.org/docs/handbook/intro-to-js-ts.html) for additional information
- See [JSDoc Reference](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html) for additional information

### Getting Started

```ts
// @ts-check

/**
 * Adds two numbers.
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */
function add(a, b) {
  return a + b;
}
```

### Objects and Interfaces

```ts
// @ts-check

/**
 * @param {{ firstName: string, lastName: string, age?: number }} person
 */
function greet(person) {
  return `Hello, ${person.firstName} ${person.lastName}`;
}

greet({ firstName: 'John', lastName: 'Doe' }); // OK
greet({ firstName: 'Jane' });
  // Error: Property 'lastName' is missing
```

### Type Definitions with @typedef

```ts
// @ts-check

/**
 * @typedef {Object} User
 * @property {number} id - The user ID
 * @property {string} username - The username
 * @property {string} [email] - Optional email address
 * @property {('admin'|'user'|'guest')} role - User role
 * @property {() => string} getFullName - Method that returns full name
 */

/** @type {User} */
const currentUser = {
  id: 1,
  username: 'johndoe',
  role: 'admin',
  getFullName() {
    return 'John Doe';
  }
};

// TypeScript will provide autocomplete for User properties
console.log(currentUser.role);
```

### Intersection Types

```ts
// @ts-check

/** @typedef {{ x: number, y: number }} Point */

/**
 * @typedef {Point & { z: number }} Point3D
 */

/** @type {Point3D} */
const point3d = { x: 1, y: 2, z: 3 };

// @ts-expect-error - missing z property
const point2d = { x: 1, y: 2 };
```

### Function Types - Basic

```ts
// @ts-check

/**
 * Calculates the area of a rectangle
 * @param {number} width - The width of the rectangle
 * @param {number} height - The height of the rectangle
 * @returns {number} The calculated area
 */
function calculateArea(width, height) {
  return width * height;
}

// TypeScript knows the parameter and return types
const area = calculateArea(10, 20);
```

### Function Types - Callbacks

```ts
// @ts-check

/**
 * @callback StringProcessor
 * @param {string} input
 * @returns {string}
 */

/**
 * @type {StringProcessor}
 */
const toUpperCase = (str) => str.toUpperCase();

/**
 * @param {string[]} strings
 * @param {StringProcessor} processor
 * @returns {string[]}
 */
function processStrings(strings, processor) {
  return strings.map(processor);
}

const result = processStrings(['hello', 'world'], toUpperCase);
// result will be ['HELLO', 'WORLD']
```

### Function Overloads

```ts
// @ts-check

/**
 * @overload
 * @param {string} a
 * @param {string} b
 * @returns {string}
 */
/**
 * @overload
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */
/**
 * @param {string | number} a
 * @param {string | number} b
 * @returns {string | number}
 */
function add(a, b) {
  if (typeof a === 'string' || typeof b === 'string') {
    return String(a) + String(b);
  }
  return a + b;
}

const strResult = add('Hello, ', 'World!'); // string
const numResult = add(10, 20);             // number
```

### Advanced Types - Union and Intersection

```ts
// @ts-check

/** @typedef {{ name: string, age: number }} Person */
/** @typedef {Person & { employeeId: string }} Employee */
/** @typedef {Person | { guestId: string, visitDate: Date }} Visitor */

/** @type {Employee} */
const employee = {
  name: 'Alice',
  age: 30,
  employeeId: 'E123'
};

/** @type {Visitor} */
const guest = {
  guestId: 'G456',
  visitDate: new Date()
};

/**
 * @param {Visitor} visitor
 * @returns {string}
 */
function getVisitorId(visitor) {
  if ('guestId' in visitor) {
    return visitor.guestId;  // TypeScript knows this is a guest
  }
  return visitor.name;      // TypeScript knows this is a Person
}
```

### Advanced Types - Mapped Types

```ts
// @ts-check

/**
 * @template T
 * @typedef {[K in keyof T]: T[K] extends Function ? K : never}[keyof T] MethodNames
 */

/**
 * @template T
 * @typedef {{[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]}} Getters
 */

/** @type {Getters<{ name: string, age: number }>} */
const userGetters = {
  getName: () => 'John',
  getAge: () => 30
};

// TypeScript enforces the return types
const name = userGetters.getName(); // string
const age = userGetters.getAge();   // number
```

### Type Imports

```ts
// @ts-check

// Importing types from TypeScript files
/** @typedef {import('./types').User} User */

// Importing types from node_modules
/** @typedef {import('http').IncomingMessage} HttpRequest */

// Importing with renaming
/** @typedef {import('./api').default as ApiClient} ApiClient */
```

### Create a types.d.ts file

```ts
// types.d.ts
declare module 'my-module' {
  export interface Config {
    [REDACTED_SECRET];
    timeout?: number;
    retries?: number;
  }

  export function initialize(config: Config): void;
  export function fetchData<T = any>(url: string): Promise<T>;
}
```

### Using type imports in JavaScript

```ts
// @ts-check

/** @type {import('my-module').Config} */
const config = {
  apiKey: '12345',
  timeout: 5000
};

// TypeScript will provide autocomplete and type checking
import { initialize } from 'my-module';
initialize(config);
```

### Create a types.d.ts file in your project

```ts
// types.d.ts
declare module 'my-module' {
  export interface Config {
    [REDACTED_SECRET];
    timeout?: number;
    retries?: number;
  }

  export function initialize(config: Config): void;
  export function fetchData<T = any>(url: string): Promise<T>;
}
```

#### Then use it in your JavaScript files

```ts
// @ts-check

/** @type {import('my-module').Config} */
const config = {
  apiKey: '12345',
  timeout: 5000
};

// TypeScript will provide autocomplete and type checking
import { initialize } from 'my-module';
initialize(config);
```

## TypeScript Migration

- Reference material for [Migration](https://www.w3schools.com/typescript/typescript_migration.php)
- See [Migrating from JavaScript](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html) for additional information

### Create a new branch for the migration

```ts
git checkout -b typescript-migration

# Commit your current state
git add .
git commit -m "Pre-TypeScript migration state"
```

### Configuration

```ts
# Install TypeScript as a dev dependency
npm install --save-dev typescript @types/node
```

### Create a basic tsconfig.json to start with:Configuration

```ts
{
    "compilerOptions": {
      "target": "ES2020",
      "module": "commonjs",
      "strict": true,
      "esModuleInterop": true,
      "skipLibCheck": true,
      "forceConsistentCasingInFileNames": true,
      "outDir": "./dist",
      "rootDir": "./src"
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules"]
}
```

> [!Note]
> Adjust the target based on your minimum supported environments.

### Create a basic tsconfig.json with these recommended settings:Step-by-Step Migration

```ts
{
    "compilerOptions": {
      "target": "ES2020",
      "module": "commonjs",
      "strict": true,
      "esModuleInterop": true,
      "skipLibCheck": true,
      "forceConsistentCasingInFileNames": true,
      "outDir": "./dist",
      "rootDir": "./src",
      "allowJs": true,
      "checkJs": true,
      "noEmit": true
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules", "dist"]
}
```

### Add // @ts-check to the top of your JavaScript files to enable type checking:Step-by-Step Migration

```ts
// @ts-check

/** @type {string} */
const name = 'John';

// TypeScript will catch this error
name = 42;
// Error: Type '42' is not assignable to type 'string'
```

> [!Note]
> You can disable type checking for specific lines using // @ts-ignore.

### Start with non-critical files and rename them from .js to .ts:Step-by-Step Migration

```ts
# Rename a single file
mv src/utils/helpers.js src/utils/helpers.ts

# Or rename all files in a directory (use with caution)
find src/utils -name "*.js" -exec sh -c 'mv "$0" "${0%.js}.ts"' {} \;
```

### Gradually add type annotations to your code:Step-by-Step Migration

```ts
// Before
function add(a, b) {
  return a + b;
}

// After
function add(a: number, b: number): number {
  return a + b;
}

// With interface
interface User {
  id: number;
  name: string;
  email?: string;
}

function getUser(id: number): User {
  return { id, name: 'John Doe' };
}
```

### Modify your package.json to include TypeScript compilation:Step-by-Step Migration

```ts
  {
    "scripts": {
      "build": "tsc",
      "dev": "tsc --watch",
      "test": "jest"
    }
  }
```

> [!Note]
> Make sure to update your test configuration to work with TypeScript files.

### Best Practices for Migration

```ts
  // Use type inference where possible
  const name = 'John';  // TypeScript infers 'string'
  const age = 30;       // TypeScript infers 'number'

  // Use union types for flexibility
  type Status = 'active' | 'inactive' | 'pending';

  // Use type guards for runtime checks
  function isString(value: any): value is string {
    return typeof value === 'string';
  }
```

### Common Challenges and Solutions

```ts
  // Before
  const user = {};
  user.name = 'John';
  // Error: Property 'name' does not exist
```

### Common Challenges and Solutions

```ts
  // Option 1: Index signature
  interface User {
    [key: string]: any;
  }
  const user: User = {};
  user.name = 'John';  // OK

  // Option 2: Type assertion
  const user = {} as { name: string };
  user.name = 'John';  // OK
```

### Common Challenges and Solutions

```ts
  class Counter {
    count = 0;
    increment() {
      setTimeout(function() {
        this.count++;
        // Error: 'this' is not defined
      }, 1000);
    }
  }
```

### Common Challenges and Solutions

```ts
  // Solution 1: Arrow function
  setTimeout(() => {
    this.count++;  // 'this' is lexically scoped
  }, 1000);

  // Solution 2: Bind 'this'
  setTimeout(function(this: Counter) {
    this.count++;
  }.bind(this), 1000);
```

## TypeScript Error Handling

- Reference material for [Error Handling](https://www.w3schools.com/typescript/typescript_error_handling.php)
- See [The Basics](https://www.typescriptlang.org/docs/handbook/2/basic-types.html) for additional information
- See [Narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html) for additional information

### Basic Error Handling

```ts
function divide(a: number, b: number): number {
  if (b === 0) {
    throw new Error('Division by zero');
  }
  return a / b;
}

try {
  const result = divide(10, 0);
  console.log(result);
} catch (error) {
  console.error('An error occurred:', error.message);
}
```

### Custom Error Classes

```ts
class ValidationError extends Error {
  constructor(message: string, public field?: string) {
    super(message);
    this.name = 'ValidationError';
    // Restore prototype chain
    Object.setPrototypeOf(this, ValidationError.prototype);
  }
}

class DatabaseError extends Error {
  constructor(message: string, public code: number) {
    super(message);
    this.name = 'DatabaseError';
    Object.setPrototypeOf(this, DatabaseError.prototype);
  }
}

// Usage
function validateUser(user: any) {
  if (!user.name) {
    throw new ValidationError('Name is required', 'name');
  }
  if (!user.email.includes('@')) {
    throw new ValidationError('Invalid email format', 'email');
  }
}
```

### Type Guards for Errors

```ts
// Type guards
function isErrorWithMessage(error: unknown): error is { message: string } {
  return (
    typeof error === 'object' &&
    error !== null &&
    'message' in error &&
    typeof (error as Record<string, any>).message === 'string'
  );
}

function isValidationError(error: unknown): error is ValidationError {
  return error instanceof ValidationError;
}

// Usage in catch block
try {
  validateUser({});
} catch (error: unknown) {
  if (isValidationError(error)) {
    console.error(`Validation error in ${error.field}: ${error.message}`);
  } else if (isErrorWithMessage(error)) {
    console.error('An error occurred:', error.message);
  } else {
    console.error('An unknown error occurred');
  }
}
```

### Type Assertion Functions

```ts
function assertIsError(error: unknown): asserts error is Error {
  if (!(error instanceof Error)) {
    throw new Error('Caught value is not an Error instance');
  }
}

try {
  // ...
} catch (error) {
  assertIsError(error);
  console.error(error.message); // TypeScript now knows error is Error
}
```

### Async Error Handling

```ts
interface User {
  id: number;
  name: string;
  email: string;
}

// Using async/await with try/catch
async function fetchUser(userId: number): Promise<User> {
  try {
    const response = await fetch(`/api/users/${userId}`);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return await response.json() as User;
  } catch (error) {
    if (error instanceof Error) {
      console.error('Failed to fetch user:', error.message);
    }
    throw error; // Re-throw to allow caller to handle
  }
}

// Using Promise.catch() for error handling
function fetchUserPosts(userId: number): Promise<any[]> {
  return fetch(`/api/users/${userId}/posts`)
    .then(response => {
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      return response.json();
    })
    .catch(error => {
      console.error('Failed to fetch posts:', error);
      return []; // Return empty array as fallback
    });
}
```

### Always Handle Promise Rejections

```ts
// Bad: Unhandled promise rejection
fetchData().then(data => console.log(data));

// Good: Handle both success and error cases
fetchData()
  .then(data => console.log('Success:', data))
  .catch(error => console.error('Error:', error));

// Or use void for intentionally ignored errors
void fetchData().catch(console.error);
```

### Best Practices - Don't Swallow Errors

```ts
// Bad: Silent failure
try { /* ... */ } catch { /* empty */ }

// Good: At least log the error
try { /* ... */ } catch (error) {
  console.error('Operation failed:', error);
}
```

### Best Practices - Use Custom Error Types

```ts
class NetworkError extends Error {
  constructor(public status: number, message: string) {
    super(message);
    this.name = 'NetworkError';
  }
}

class ValidationError extends Error {
  constructor(public field: string, message: string) {
    super(message);
    this.name = 'ValidationError';
  }
}
```

### Best Practices - Handle Errors at Appropriate Layers

```ts
// In a data access layer
async function getUser(id: string): Promise<User> {
  const response = await fetch(`/api/users/${id}`);
  if (!response.ok) {
    throw new NetworkError(response.status, 'Failed to fetch user');
  }
  return response.json();
}

// In a UI component
async function loadUser() {
  try {
    const user = await getUser('123');
    setUser(user);
  } catch (error) {
    if (error instanceof NetworkError) {
      if (error.status === 404) {
        showError('User not found');
      } else {
        showError('Network error. Please try again later.');
      }
    } else {
      showError('An unexpected error occurred');
    }
  }
}
```

## TypeScript Best Practices

- Reference material for [Best Practices](https://www.w3schools.com/typescript/typescript_best_practices.php)
- See [The TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html) for additional information
- See [Do's and Don'ts](https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html) for additional information

### Project Configuration - Enable Strict Mode

```json
// tsconfig.json
{
  "compilerOptions": {
    /* Enable all strict type-checking options */
    "strict": true,
    /* Additional recommended settings */
    "target": "ES2020",
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}
```

### Project Configuration - Additional Strict Checks

```json
{
  "compilerOptions": {
    /* Additional strict checks */
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true
  }
}
```

### Type System - Let TypeScript Infer

```ts
// Bad: Redundant type annotation
const name: string = 'John';

// Good: Let TypeScript infer the type
const name = 'John';

// Bad: Redundant return type
function add(a: number, b: number): number {
  return a + b;
}

// Good: Let TypeScript infer return type
function add(a: number, b: number) {
  return a + b;
}
```

### Type System - Be Explicit with Public APIs

```ts
// Bad: No type information
function processUser(user) {
  return user.name.toUpperCase();
}

// Good: Explicit parameter and return types
interface User {
  id: number;
  name: string;
  email?: string;  // Optional property
}

function processUser(user: User): string {
  return user.name.toUpperCase();
}
```

### Type System - Interface vs Type

```ts
// Use interface for object shapes that can be extended/implemented
interface User {
  id: number;
  name: string;
}

// Extending an interface
interface AdminUser extends User {
  permissions: string[];
}

// Use type for unions, tuples, or mapped types
type UserRole = 'admin' | 'editor' | 'viewer';

// Union types
type UserId = number | string;

// Mapped types
type ReadonlyUser = Readonly<User>;

// Tuple types
type Point = [number, number];
```

### Type System - Prefer Specific Types Over 'any'

```ts
// Bad: Loses type safety
function logValue(value: any) {
  console.log(value.toUpperCase()); // No error until runtime
}

// Better: Use generic type parameter
function logValue<T>(value: T) {
  console.log(String(value)); // Safer, but still not ideal
}

// Best: Be specific about expected types
function logString(value: string) {
  console.log(value.toUpperCase()); // Type-safe
}

// When you need to accept any value but still be type-safe
function logUnknown(value: unknown) {
  if (typeof value === 'string') {
    console.log(value.toUpperCase());
  } else {
    console.log(String(value));
  }
}
```

### Code Organization - Logical Modules

```ts
// user/user.model.ts
export interface User {
  id: string;
  name: string;
  email: string;
}

// user/user.service.ts
import { User } from './user.model';

export class UserService {
  private users: User[] = [];

  addUser(user: User) {
    this.users.push(user);
  }

  getUser(id: string): User | undefined {
    return this.users.find(user => user.id === id);
  }
}

// user/index.ts (barrel file)
export * from './user.model';
export * from './user.service';
```

### Code Organization - File Naming Patterns

```ts
// Good
user.service.ts      // Service classes
user.model.ts        // Type definitions
user.controller.ts   // Controllers
user.component.ts    // Components
user.utils.ts        // Utility functions
user.test.ts         // Test files

// Bad
UserService.ts       // Avoid PascalCase for file names
user_service.ts      // Avoid snake_case
userService.ts       // Avoid camelCase for file names
```

### Functions and Methods - Type-Safe Functions

```ts
// Bad: No type information
function process(user, notify) {
  notify(user.name);
}

// Good: Explicit parameter and return types
function processUser(
  user: User,
  notify: (message: string) => void
): void {
  notify(`Processing user: ${user.name}`);
}

// Use default parameters instead of conditionals
function createUser(
  name: string,
  role: UserRole = 'viewer',
  isActive: boolean = true
): User {
  return { name, role, isActive };
}

// Use rest parameters for variable arguments
function sum(...numbers: number[]): number {
  return numbers.reduce((total, num) => total + num, 0);
}
```

### Functions and Methods - Single Responsibility

```ts
// Bad: Too many responsibilities
function processUserData(userData: any) {
  // Validation
  if (!userData || !userData.name) throw new Error('Invalid user data');

  // Data transformation
  const processedData = {
    ...userData,
    name: userData.name.trim(),
    createdAt: new Date()
  };

  // Side effect
  saveToDatabase(processedData);

  // Notification
  sendNotification(processedData.email, 'Profile updated');

  return processedData;
}

// Better: Split into smaller, focused functions
function validateUserData(data: unknown): UserData {
  if (!data || typeof data !== 'object') {
    throw new Error('Invalid user data');
  }
  return data as UserData;
}

function processUserData(userData: UserData): ProcessedUserData {
  return {
    ...userData,
    name: userData.name.trim(),
    createdAt: new Date()
  };
}
```

### Async/Await Patterns - Proper Error Handling

```ts
// Bad: Not handling errors
async function fetchData() {
  const response = await fetch('/api/data');
  return response.json();
}

// Good: Proper error handling
async function fetchData<T>(url: string): Promise<T> {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return await response.json() as T;
  } catch (error) {
    console.error('Failed to fetch data:', error);
    throw error; // Re-throw to allow caller to handle
  }
}

// Better: Use Promise.all for parallel operations
async function fetchMultipleData<T>(urls: string[]): Promise<T[]> {
  try {
    const promises = urls.map(url => fetchData<T>(url));
    return await Promise.all(promises);
  } catch (error) {
    console.error('One or more requests failed:', error);
    throw error;
  }
}

// Example usage
interface User {
  id: string;
  name: string;
  email: string;
}

// Fetch user data with proper typing
async function getUserData(userId: string): Promise<User> {
  return fetchData<User>(`/api/users/${userId}`);
}
```

### Async/Await Patterns - Flatten Code

```ts
// Bad: Nested async/await (callback hell)
async function processUser(userId: string) {
  const user = await getUser(userId);
  if (user) {
    const orders = await getOrders(user.id);
    if (orders.length > 0) {
      const latestOrder = orders[0];
      const items = await getOrderItems(latestOrder.id);
      return { user, latestOrder, items };
    }
  }
  return null;
}

// Better: Flatten the async/await chain
async function processUser(userId: string) {
  const user = await getUser(userId);
  if (!user) return null;

  const orders = await getOrders(user.id);
  if (orders.length === 0) return { user, latestOrder: null, items: [] };

  const latestOrder = orders[0];
  const items = await getOrderItems(latestOrder.id);

  return { user, latestOrder, items };
}

// Best: Use Promise.all for independent async operations
async function processUser(userId: string) {
  const [user, orders] = await Promise.all([
    getUser(userId),
    getOrders(userId)
  ]);

  if (!user) return null;
  if (orders.length === 0) return { user, latestOrder: null, items: [] };

  const latestOrder = orders[0];
  const items = await getOrderItems(latestOrder.id);

  return { user, latestOrder, items };
}
```

### Testing and Quality - Dependency Injection

```ts
// Bad: Hard to test due to direct dependencies
class PaymentProcessor {
  async processPayment(amount: number) {
    const paymentGateway = new PaymentGateway();
    return paymentGateway.charge(amount);
  }
}

// Better: Use dependency injection
interface PaymentGateway {
  charge(amount: number): Promise<boolean>;
}

class PaymentProcessor {
  constructor(private paymentGateway: PaymentGateway) {}

  async processPayment(amount: number): Promise<boolean> {
    if (amount <= 0) {
      throw new Error('Amount must be greater than zero');
    }
    return this.paymentGateway.charge(amount);
  }
}

// Test example with Jest
describe('PaymentProcessor', () => {
  let processor: PaymentProcessor;
  let mockGateway: jest.Mocked<PaymentGateway>;

  beforeEach(() => {
    mockGateway = {
      charge: jest.fn()
    };
    processor = new PaymentProcessor(mockGateway);
  });

  it('should process a valid payment', async () => {
    mockGateway.charge.mockResolvedValue(true);
    const result = await processor.processPayment(100);
    expect(result).toBe(true);
    expect(mockGateway.charge).toHaveBeenCalledWith(100);
  });

  it('should throw for invalid amount', async () => {
    await expect(processor.processPayment(-50))
      .rejects.toThrow('Amount must be greater than zero');
  });
});
```

### Testing and Quality - Type Testing

```ts
// Using @ts-expect-error to test for type errors
// @ts-expect-error - Should not allow negative values
const invalidUser: User = { id: -1, name: 'Test' };

// Using type assertions in tests
function assertIsString(value: unknown): asserts value is string {
  if (typeof value !== 'string') {
    throw new Error('Not a string');
  }
}

// Using utility types for testing
type IsString<T> = T extends string ? true : false;
type Test1 = IsString<string>;  // true
type Test2 = IsString<number>;  // false

// Using tsd for type testing (install with: npm install --save-dev tsd)
/*
import { expectType } from 'tsd';

const user = { id: 1, name: 'John' };
expectType<{ id: number; name: string }>(user);
expectType<string>(user.name);
*/
```

### Performance - Type-Only Imports

```ts
// Bad: Imports both type and value
import { User, fetchUser } from './api';

// Good: Separate type and value imports
import type { User } from './api';
import { fetchUser } from './api';

// Even better: Use type-only imports when possible
import type { User, UserSettings } from './types';

// Type-only export
export type { User };

// Runtime export
export { fetchUser };

// In tsconfig.json, enable "isolatedModules": true
// to ensure type-only imports are properly handled
```

### Performance - Avoid Complex Types

```ts
// Bad: Deeply nested mapped types can be slow
type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

// Better: Use built-in utility types when possible
type User = {
  id: string;
  profile: {
    name: string;
    email: string;
  };
  preferences?: {
    notifications: boolean;
  };
};

// Instead of DeepPartial<User>, use Partial with type assertions
const updateUser = (updates: Partial<User>) => {
  // Implementation
};

// For complex types, consider using interfaces
interface UserProfile {
  name: string;
  email: string;
}

interface UserPreferences {
  notifications: boolean;
}

interface User {
  id: string;
  profile: UserProfile;
  preferences?: UserPreferences;
}
```

### Performance - Const Assertions

```ts
// Without const assertion (wider type)
const colors = ['red', 'green', 'blue'];
// Type: string[]

// With const assertion (narrower, more precise type)
const colors = ['red', 'green', 'blue'] as const;
// Type: readonly ["red", "green", "blue"]

// Extract union type from const array
type Color = typeof colors[number];  // "red" | "green" | "blue"

// Objects with const assertions
const config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
  features: ['auth', 'notifications'],
} as const;

// Type is:
// {
//   readonly apiUrl: "https://api.example.com";
//   readonly timeout: 5000;
//   readonly features: readonly ["auth", "notifications"];
// }
```

### Common Mistakes - Avoid 'any'

```ts
// Bad: Loses all type safety
function process(data: any) {
  return data.map(item => item.name);
}

// Better: Use generics for type safety
function process<T extends { name: string }>(items: T[]) {
  return items.map(item => item.name);
}

// Best: Use specific types when possible
interface User {
  name: string;
  age: number;
}

function processUsers(users: User[]) {
  return users.map(user => user.name);
}
```

### Common Mistakes - Enable Strict Mode

```json
// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    /* Additional strictness flags */
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true
  }
}
```

### Common Mistakes - Let TypeScript Infer

```ts
// Redundant type annotation
const name: string = 'John';

// Let TypeScript infer the type
const name = 'John';  // TypeScript knows it's a string

// Redundant return type
function add(a: number, b: number): number {
  return a + b;
}

// Let TypeScript infer the return type
function add(a: number, b: number) {
  return a + b;  // TypeScript infers number
}
```

### Common Mistakes - Use Type Guards

```ts
// Without type guard
function process(input: string | number) {
  return input.toUpperCase();  // Error: toUpperCase doesn't exist on number
}

// With type guard
function isString(value: unknown): value is string {
  return typeof value === 'string';
}

function process(input: string | number) {
  if (isString(input)) {
    return input.toUpperCase();  // TypeScript knows input is string here
  } else {
    return input.toFixed(2);  // TypeScript knows input is number here
  }
}

// Built-in type guards
if (typeof value === 'string') { /* value is string */ }
if (value instanceof Date) { /* value is Date */ }
if ('id' in user) { /* user has id property */ }
```

### Common Mistakes - Handle Null/Undefined

```ts
// Bad: Potential runtime error
function getLength(str: string | null) {
  return str.length;  // Error: Object is possibly 'null'
}

// Good: Null check
function getLength(str: string | null) {
  if (str === null) return 0;
  return str.length;
}

// Better: Use optional chaining and nullish coalescing
function getLength(str: string | null) {
  return str?.length ?? 0;
}

// For arrays
const names: string[] | undefined = [];
const count = names?.length ?? 0;  // Safely handle undefined

// For object properties
interface User {
  profile?: {
    name?: string;
  };
}

const user: User = {};
const name = user.profile?.name ?? 'Anonymous';
```


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)