TypeScript: Static Typing for Large-Scale JavaScript Applications
Type System Fundamentals and Strict Mode
TypeScript adds static type checking to JavaScript: declare variable type (string, number, boolean, object), compiler verifies type usage. Basic types: const name: string = 'John', const age: number = 30, const active: boolean = true. Type inference: const name = 'John' automatically inferred as string (no annotation needed). Strict mode: tsconfig.json { "strict": true } enforces strict checking. Strict mode enables: noImplicitAny (any type banned unless explicit), strictNullChecks (null/undefined must be handled), strictFunctionTypes (parameter/return types checked). Without strict: let x; x = 5; x = 'hello'; (allowed, confusing). With strict: error unless explicitly typed (union type). Benefit: prevents 30-50% of runtime errors (type-related bugs). Performance: compile-time checking (0 runtime overhead), TypeScript erased from final JavaScript.
Interfaces and Type Aliases
Interfaces: describe object shape. interface User { name: string; age: number; email?: string }. Optional property (email?) can be undefined. Functions: function getUser(id: number): User { ... } returns User object. Type checking: calling getUser(123) returns object with name/age/email (compile-time verified). Inheritance: interface Admin extends User { role: 'admin' | 'moderator' }. Type aliases: type Point = { x: number; y: number }. Difference: interfaces are "open-ended" (can be re-declared, merged), types are "closed" (single declaration). Both support: readonly properties (modify detection), methods, computed properties. Advanced: interface Document { [key: string]: any } allows any property (flexible).
Generics and Type Reusability
Generics: write reusable functions with type variables. function identity(arg: T): T { return arg; }. Caller specifies type: identity
Type Narrowing and Type Guards
Type narrowing: reduce type from broader to narrower. Union types: function process(input: string | number) { ... }. Without narrowing: input.toUpperCase() throws error (number lacks toUpperCase). Type guards: if (typeof input === 'string') { input.toUpperCase() } (narrowed to string). Instanceof checks: if (error instanceof Error) { error.message } (narrow to Error class). Type predicates: function isUser(obj: any): obj is User { return obj.name && obj.age } (custom guard). Truthiness narrowing: if (value) { ... } eliminates null/undefined/falsy values. Exhaustive checking: type Status = 'pending' | 'complete' | 'error'; switch(status) { case 'pending': ...; case 'complete': ...; case 'error': ...; default: const impossible: never = status } (compile error if case missed).
Advanced Features and Performance
Decorators: @deprecated, @readonly modify class behavior (experimental). Example: @memoize function caches results (functional decoration). Enums: enum Direction { Up = 0, Down = 1, Left = 2, Right = 3 }. Reverse mapping: Direction[0] === 'Up' (allows name lookup). String enums: enum Color { Red = 'red', Green = 'green' } (more readable). Conditional types: type IsString
Integration with Tools and Best Practices
IDE support: VSCode provides real-time type checking, autocomplete suggestions (50+ milliseconds lag eliminated vs JavaScript debugging). Linting: ESLint + typescript-eslint catches style/type issues. Testing: Jest + @types/jest type-safe test cases. Compilation: tsc (TypeScript compiler) generates JavaScript. Watch mode: tsc --watch recompiles on file change (<100ms). Build optimization: incremental builds cache intermediate results (30% faster rebuilds). Source maps: sourcemap: true maps compiled JS back to TS for debugging. Production: ship JavaScript (no TS runtime), tree-shake unused types (0 bundle overhead). Library publishing: @types/package provides types for untyped JS libraries. Breaking changes: version bump signals type compatibility (semver for types).
Common Pitfalls and Anti-Patterns
any type: defeats type checking (avoid). Instead use unknown (must narrow before use) or generic types. Example: function process(data: any) { ... } allows bug (misspelled property passes). Better: function process