🚀 TypeScript Introduction
🎯 Complete Definition
TypeScript is a strongly typed, object-oriented, compiled programming language developed and maintained by Microsoft. It is a strict syntactical superset of JavaScript that adds optional static typing to the language. TypeScript is designed for the development of large applications and transcompiles to JavaScript.
Key Features: Static typing with type inference, interfaces, classes, modules, decorators, generics, enums, and advanced type systems. TypeScript code is compiled to plain JavaScript, which can run on any browser, Node.js, or any JavaScript engine.
History: Created by Anders Hejlsberg (creator of C#) in 2012. Current version: TypeScript 5.0+. Major adoption by Angular (default), React, Vue.js, and Node.js communities.
Benefits: Early error detection, better code documentation, enhanced IDE support with IntelliSense, refactoring tools, and improved code maintainability for large-scale applications.
Compiler: tsc (TypeScript Compiler) transforms .ts files to .js. Supports various module systems (CommonJS, AMD, ES Modules) and target ECMAScript versions (ES5, ES2015-ES2022).
Type System: Structural typing (duck typing) rather than nominal typing. Type compatibility is based on shape, not name. Supports type inference to reduce verbosity while maintaining type safety.
Ecosystem: Extensive DefinitelyTyped repository for type definitions of JavaScript libraries. Integrated with all major build tools (Webpack, Rollup, Vite) and testing frameworks.
📊 Basic Types
🎯 Complete Definition
TypeScript provides several basic types: boolean, number, string, array, tuple, enum, any, void, null, undefined, never, object, and symbol. Type annotations are added using colon syntax (variable: type).
Boolean: true/false values. Number: All numbers are floating point, includes hexadecimal, binary, and octal literals. String: Text data with support for template strings.
Array: Can be declared as type[] or Array
Any: Opt-out of type checking - use sparingly. Void: Absence of type, commonly used as function return type. Null/Undefined: Subtypes of all other types when strictNullChecks is false.
Never: Represents values that never occur (function that always throws, infinite loop). Object: Non-primitive type. Unknown: Type-safe counterpart of any (TypeScript 3.0).
Literal Types: Exact values as types (let x: "hello" = "hello"). Union Types: Values that can be one of several types (string | number). Intersection Types: Combines multiple types into one (TypeA & TypeB).
Type Aliases: Create new names for types using type keyword. Type Assertions: Tell compiler "trust me, I know what I'm doing" using as syntax or angle brackets.
Type Inference: TypeScript can infer types when variables are initialized, reducing need for explicit annotations while maintaining type safety.
🔧 Interfaces
🎯 Complete Definition
Interfaces in TypeScript are powerful way to define contracts within your code and contracts with code outside of your project. They define the shape that values must have and can be used to type-check objects, functions, classes, and more.
Object Shape: Interfaces primarily describe object shapes - the properties they should have and their types. They support optional properties (?), readonly properties, and excess property checks.
Function Types: Interfaces can describe function types by defining a call signature. This specifies the parameter types and return type of a function.
Indexable Types: Interfaces can describe types that can be indexed into like arrays or dictionaries. Use index signatures: [index: type]: returnType.
Class Implementation: Classes can implement interfaces to ensure they meet a particular contract. A class can implement multiple interfaces.
Extending Interfaces: Interfaces can extend other interfaces (single or multiple), inheriting their members. This allows for building up complex interfaces from simpler ones.
Hybrid Types: Interfaces can describe objects that work as both functions and objects with additional properties. Common in JavaScript patterns.
Difference from Type Aliases: Interfaces create a new name that can be used anywhere. Type aliases don't create a new name. Interfaces can be extended and implemented; type aliases can use intersections. Interfaces support declaration merging.
Declaration Merging: When multiple interface declarations with the same name exist, TypeScript merges them into a single interface with combined members. Useful for extending existing interfaces.
Utility: Interfaces provide better error messages, are displayed in IDE tooltips, and work well with IntelliSense. They're essential for defining APIs and library contracts.
🏗️ Classes
🎯 Complete Definition
Classes in TypeScript bring traditional object-oriented programming with classes, inheritance, and static typing. TypeScript classes compile to plain JavaScript functions to simulate classes (prior to ES6) or use native ES6 class syntax when targeting ES6+.
Class Members: Properties (fields) and methods. Can have public (default), private, or protected modifiers. TypeScript also adds readonly modifier and parameter properties for concise property declaration.
Constructors: Special method for creating and initializing objects. Can have parameters that automatically become properties using parameter properties (public/private/protected/readonly before parameter name).
Inheritance: Use extends keyword. Derived classes (subclasses) inherit from base classes (superclasses). Can override methods with super keyword to call base class implementation.
Access Modifiers: public (accessible anywhere), private (only within class), protected (within class and derived classes). TypeScript 3.8 adds # for true private fields following ES2022.
Abstract Classes: Cannot be instantiated directly, meant to be base classes. Can contain abstract methods (no implementation) that must be implemented by derived classes.
Static Properties: Belong to class itself, not instances. Accessed via ClassName.propertyName.
Getters/Setters: Accessor functions that look like properties. Useful for validation, computed properties, or encapsulation.
Implementing Interfaces: Classes can implement one or more interfaces, ensuring they provide implementations for all required members.
this Parameter: Functions can have explicitly typed this parameter to ensure correct context. Arrow functions capture this lexically.
Advanced Features: Mixins for multiple inheritance patterns, decorators for meta-programming, and strict property initialization checks.
⚙️ Functions
🎯 Complete Definition
Functions are the fundamental building block in TypeScript, as in JavaScript. TypeScript adds type annotations to function parameters and return values, enabling better documentation and error checking.
Function Types: Functions can be typed using function type expressions: (param: type) => returnType. This is useful for callbacks and higher-order functions.
Optional and Default Parameters: Parameters can be optional using ? or have default values. Optional parameters must come after required parameters.
Rest Parameters: Collect multiple arguments into an array using ... syntax. Must be the last parameter and typed as an array.
this Parameter: TypeScript can track the type of this in functions. Arrow functions capture this lexically from their surrounding context.
Function Overloads: TypeScript allows multiple function signatures for the same function implementation. Useful for functions that can be called in different ways.
Generic Functions: Functions can have type parameters to work with multiple types while maintaining type safety. Constraints can be applied using extends.
Contextual Typing: TypeScript can infer function parameter types based on context, especially useful for callbacks passed to array methods or event handlers.
Void Return Type: Indicates function doesn't return a value. Different from undefined return type - void allows returning undefined or null (with strictNullChecks off).
Never Return Type: Functions that never return (always throw exception or infinite loop) should have never return type.
Function Declarations vs Expressions: Function declarations are hoisted; function expressions are not. Arrow functions have concise syntax and lexical this.
Immediately Invoked Function Expressions (IIFE): Functions that are executed immediately after creation. Useful for creating scopes.
🎭 Generics
🎯 Complete Definition
Generics enable creating reusable components that work with multiple types while maintaining type safety. They allow types to be parameters, similar to function parameters.
Generic Functions: Functions that can work with any type. Type parameters are specified in angle brackets before parameters. TypeScript can often infer type arguments from usage.
Generic Interfaces: Interfaces that have type parameters. Can be used to describe objects, functions, or classes that work with multiple types.
Generic Classes: Classes with type parameters. Type parameters can be used for property types, method parameters, and return types.
Generic Constraints: Use extends keyword to constrain type parameters to certain shapes. Ensures type parameter has certain properties or capabilities.
Using Type Parameters in Generic Constraints: Constrain type parameter to be property of another type parameter. Useful for keyof operations.
Generic Defaults: TypeScript 2.3 added default types for generic parameters. Useful when type can be inferred from usage but you want a fallback.
Generic Utility Types: TypeScript provides built-in generic utility types: Partial
Mapped Types: Create new types based on old types by transforming properties. Use keyof and indexed access types. Commonly used in utility types.
Conditional Types: Types that depend on type relationships. Syntax: T extends U ? X : Y. Used for type-level logic and inference.
Infer Keyword: Within conditional types, infer can capture types to be used in true branch. Used for extracting types from other types.
Generic Parameter Defaults: Specify default type for generic parameter when not provided. Makes generic types easier to use.
🔢 Enums
🎯 Complete Definition
Enums (enumerations) are a TypeScript feature that allows defining a set of named constants. They make code more readable and maintainable by giving meaningful names to numeric or string values.
Numeric Enums: Default enum type where values are auto-incremented numbers starting from 0. Can also manually set values.
String Enums: Each member must be initialized with a string literal or another string enum member. Provide meaningful and readable values.
Heterogeneous Enums: Mix of numeric and string values - generally discouraged as it's rarely useful.
Computed and Constant Members: Enum members can be constant (compile-time known) or computed (runtime expressions).
Reverse Mapping: Numeric enums create reverse mappings from values to names. String enums don't generate reverse mappings.
Const Enums: Use const modifier for enums that are completely removed during compilation. Only constant expressions allowed. Better performance.
Ambient Enums: Used to describe the shape of existing enum types. Useful for declaration files.
Enum Member Types: Each enum member has its own type. Enum types themselves become a union of each enum member.
Enums at Runtime: Enums are real objects that exist at runtime. Can be passed to functions and manipulated.
Enums at Compile Time: TypeScript uses enums for type checking. Const enums are completely removed, replaced by inline values.
Best Practices: Use string enums for better debugging experience. Use const enums for performance-critical code. Avoid heterogeneous enums.
✨ Advanced Types
🎯 Complete Definition
Advanced Type Features in TypeScript provide powerful type-level programming capabilities that enable sophisticated type safety patterns and abstractions beyond basic types.
Union Types (|): Allow a value to be one of several types. TypeScript will only allow operations that are valid for every type in the union, requiring type guards to narrow types within conditional blocks.
Intersection Types (&): Combine multiple types into one, creating a type that has all properties of each constituent type. Useful for mixin patterns and object composition.
Type Guards: Runtime checks that narrow types within conditional blocks. Built-in guards include typeof, instanceof, and the in operator. Custom type guard functions return "parameter is Type" predicate.
Discriminated Unions: A pattern using a common literal property (discriminant) to distinguish between union members. TypeScript can perform exhaustive type narrowing based on discriminant property values.
Index Types (keyof and T[K]): Use keyof to get a union of property names from a type. Use indexed access T[K] to get the type of a property. Enables type-safe property access patterns.
Mapped Types: Create new types by transforming properties of existing types using {[P in K]: T} syntax. The foundation for utility types like Partial, Readonly, Pick, and Record.
Conditional Types (T extends U ? X : Y): Types that depend on other types through conditional logic. Can be nested for complex type transformations. Essential for type-level programming.
Template Literal Types (TypeScript 4.1+): Use template literal syntax to manipulate string literal types. Enable pattern matching, concatenation, and transformation of string types at compile time.
Infer Keyword: Used within conditional types to capture types for use in the true branch. Essential for extracting types from other types (function parameters, return types, array elements).
Recursive Types: Types that reference themselves, enabling definitions of tree structures, linked lists, and nested data. TypeScript supports both interface and type alias recursion.
Branded/Nominal Types: Patterns using unique phantom properties to create nominal types in TypeScript's structural type system. Prevents accidental mixing of types that have the same structure but different semantics.
satisfies Operator (TypeScript 4.9+): Checks that an expression satisfies a constraint without widening its type to the constraint. Preserves literal types while ensuring type safety.
const Assertions (as const): Create deeply readonly literal types, preserving specific literal values rather than widening to general types. Useful for configuration objects and immutable data.
📦 Modules
🎯 Complete Definition
Modules in TypeScript provide a way to organize code into reusable, maintainable units with clear boundaries and dependencies. TypeScript supports ES modules (ECMAScript standard) and can compile to various module systems including CommonJS, AMD, SystemJS, and UMD.
Export Declaration: Make variables, functions, classes, interfaces, type aliases, and namespaces available to other modules using the export keyword. Can export individual declarations or use export statements.
Import Declaration: Bring exported declarations from other modules into current module scope using import keyword. Can import specific named exports, default exports, or entire module as namespace.
Default Exports: Each module can have exactly one default export, typically representing the main functionality. Imported without braces using any name. Best for modules that export a single primary thing.
Named Exports: Export multiple values from a module with specific names. Must be imported using matching names in braces or renamed with as keyword. Provide better IntelliSense and refactoring.
Re-exporting (Barrel Files): Export items from another module without importing them first, creating a single entry point that aggregates exports from multiple modules. Useful for library APIs and clean imports.
Namespace Imports: Import all exports from a module into a single namespace object using import * as alias. Useful when module has many exports or to avoid naming conflicts.
Dynamic Imports (import()): Import modules dynamically at runtime using import() function which returns a Promise. Essential for code splitting, lazy loading, and conditional imports.
Module Resolution: Process of resolving module specifiers to actual files. TypeScript supports two strategies: "classic" (legacy) and "node" (Node.js-style). Configured via moduleResolution in tsconfig.json.
Path Mapping: Map module names to specific file paths using baseUrl and paths compiler options. Eliminates relative path complexity with clean aliases like @/ for src/.
Declaration Files (.d.ts): TypeScript files that describe the shape of existing JavaScript modules. Can be handwritten, generated by tsc with --declaration flag, or obtained from DefinitelyTyped repository.
Ambient Modules (declare module): Declare modules that exist but aren't written in TypeScript, typically for JavaScript libraries. Provide type information for untyped modules.
Module Augmentation: Add declarations to existing modules using declare module syntax. Extend third-party module types with additional properties or methods.
ES Modules vs CommonJS: TypeScript can compile to either format using module compiler option. Modern projects prefer ES modules for tree-shaking and future compatibility.
Module Interoperability: Use esModuleInterop and allowSyntheticDefaultImports options for better compatibility between ES modules and CommonJS modules, especially with default imports.
🎀 Decorators
🎯 Complete Definition
Decorators are a special kind of declaration that can be attached to classes, methods, accessors, properties, or parameters in TypeScript. They use the form @expression where expression evaluates to a function that will be called at runtime with information about the decorated declaration.
Experimental Feature: Decorators are an experimental feature in TypeScript and require enabling with "experimentalDecorators": true in tsconfig.json. They are a Stage 3 proposal for JavaScript with ongoing standardization.
Class Decorators: Applied to class constructors. Can observe, modify, or replace class definition. Receives the constructor function as single parameter. Can return a new constructor to replace the original.
Method Decorators: Applied to method declarations. Can observe, modify, or replace method definition. Receives three parameters: target (prototype or constructor), propertyKey (method name), and descriptor (PropertyDescriptor).
Accessor Decorators: Applied to getter or setter declarations. Similar to method decorators but specifically for property accessors. Can modify get/set behavior.
Property Decorators: Applied to property declarations. Receives two parameters: target (prototype or constructor) and propertyKey (property name). Cannot directly modify property descriptor but can add metadata.
Parameter Decorators: Applied to parameter declarations in constructors or methods. Receives three parameters: target, propertyKey (or undefined for constructor), and parameterIndex. Often used with metadata reflection.
Decorator Factories: Functions that return decorator functions, allowing decorators to be configured with parameters. Enables reusable, configurable decorator patterns.
Decorator Composition: Multiple decorators can be applied to a single declaration. They're evaluated/composed from top to bottom but executed from bottom to top (factory functions run first).
Metadata Reflection: Decorators can be used with the reflect-metadata library to store and retrieve design-time type information. Requires "emitDecoratorMetadata": true in tsconfig.json.
Common Use Cases: Logging, validation, dependency injection, ORM mapping, access control, performance measurement, serialization/deserialization, caching, and aspect-oriented programming.
Framework Adoption: Used extensively in Angular (Component, Injectable, Input decorators), NestJS (Controller, Injectable), TypeORM (Entity, Column), and other TypeScript frameworks for declarative programming.
Limitations & Best Practices: Experimental feature subject to change. Some patterns require reflect-metadata polyfill. Not all decorator types can modify their targets directly. Prefer composition over complex decorator logic.
Stage 3 Proposal: The decorators proposal is at Stage 3 in TC39 process. Future JavaScript versions will have native decorator syntax, potentially different from TypeScript's current implementation.
📁 Namespaces
🎯 Complete Definition
Namespaces (formerly called "internal modules") are a TypeScript-specific way to organize code into logical groups and prevent naming collisions in the global scope. They provide containerization for related functionality.
Purpose & Use Cases: Organize code logically, prevent global namespace pollution, manage dependencies between code parts, and create library APIs. Particularly useful for large applications and libraries before widespread ES module adoption.
Declaration Syntax: Use namespace keyword (or module keyword which is equivalent) followed by name and curly braces containing namespace members. Members must be exported to be accessible from outside.
Exporting Members: Use export keyword on declarations within namespace to make them accessible. Can export variables, functions, classes, interfaces, types, and other namespaces.
Nested Namespaces: Namespaces can contain other namespaces, creating hierarchical organization. Access nested namespaces using dot notation (Namespace.SubNamespace).
Multi-file Namespaces: The same namespace can be split across multiple TypeScript files using /// <reference> directives or module bundlers. All parts contribute to the same namespace.
Ambient Namespaces: Declare namespaces for existing JavaScript libraries using declare namespace syntax in .d.ts files. Provides type information for untyped libraries.
Namespace vs ES Modules: Namespaces are TypeScript-specific using namespace keyword and file merging. ES modules use file-based organization with import/export. Modern TypeScript prefers ES modules.
Triple-Slash Directives (///): Special comments that instruct TypeScript compiler. /// <reference path="..." /> references other files containing namespace declarations. Mostly superseded by modules.
Namespace Merging: Multiple namespace declarations with the same name are automatically merged by TypeScript. Similar to interface merging but for namespaces.
Compilation Output: Namespaces compile to JavaScript objects that create or extend global objects. The --outFile compiler option can bundle multiple files into single output.
When to Use Namespaces: Legacy codebases, certain library patterns (like jQuery plugins), when targeting environments without module support, or when specific bundling behavior is needed.
Limitations & Modern Alternatives: Not part of ECMAScript standard, require special compilation handling, can't be tree-shaken. Modern projects should use ES modules with bundlers like Webpack or Rollup.
Migration Path: Can migrate from namespaces to ES modules by converting namespace exports to module exports, updating references, and using module bundlers for distribution.
🛠️ Type Utilities
🎯 Complete Definition
TypeScript's Built-in Type Utilities are generic types that provide powerful tools for common type transformations and manipulations. They're defined in the TypeScript lib files and available globally.
Partial<T>: Constructs a type with all properties of T set to optional. Useful for update operations, partial object creation, and optional configuration.
Required<T>: Constructs a type with all properties of T set to required. The opposite of Partial. Useful when you need to ensure all properties are present.
Readonly<T>: Constructs a type with all properties of T set to readonly. Properties cannot be reassigned after creation. Ensures immutability.
Record<K, T>: Constructs an object type with property keys of type K and property values of type T. Creates dictionary/map-like types with specific key and value types.
Pick<T, K>: Constructs a type by picking the set of properties K from T. Creates a subtype containing only the specified properties.
Omit<T, K>: Constructs a type by omitting the set of properties K from T. The opposite of Pick. Creates a type without the specified properties.
Exclude<T, U>: Excludes from T those types that are assignable to U. Works on union types to remove specific types.
Extract<T, U>: Extracts from T those types that are assignable to U. The opposite of Exclude. Filters union types to keep only matching types.
NonNullable<T>: Excludes null and undefined from T. Useful for ensuring a value is neither null nor undefined.
Parameters<T>: Extracts the parameter types of a function type T as a tuple. Useful for type-safe function composition and higher-order functions.
ReturnType<T>: Extracts the return type of a function type T. Essential for type inference and working with function results.
InstanceType<T>: Extracts the instance type of a constructor function type T. Gets the type of instances created by a class constructor.
ConstructorParameters<T>: Extracts the parameter types of a constructor function type T as a tuple. Similar to Parameters but for constructors.
ThisParameterType<T>: Extracts the type of the this parameter of a function type T, or unknown if the function has no this parameter.
OmitThisParameter<T>: Removes the this parameter from a function type T. Useful for creating function bindings.
Awaited<T> (TypeScript 4.5+): Unwraps a Promise type to get the type of the value it resolves to. Handles nested promises and promise-like types.
Uppercase, Lowercase, Capitalize, Uncapitalize (TypeScript 4.1+): Intrinsic string manipulation types for template literal types. Transform string literal types at compile time.
⚡ Compiler Options
🎯 Complete Definition
TypeScript Compiler Options control how TypeScript code is transpiled to JavaScript, affecting type checking, module resolution, output format, and more. Configured via tsconfig.json file or command-line flags.
Basic Configuration: target (ECMAScript target version), module (module system), lib (library files to include), outDir (output directory), rootDir (root of input files).
Strict Type-Checking Family: strict (enables all strict options), noImplicitAny (error on implied any types), strictNullChecks (strict null/undefined checking), strictFunctionTypes (strict function parameter checking).
Module Resolution: moduleResolution (how modules are resolved - "node" or "classic"), baseUrl (base directory for module resolution), paths (path mapping for module aliases).
Source Map & Declaration: sourceMap (generate .map files), inlineSourceMap (embed source maps in output), declaration (generate .d.ts declaration files), declarationMap (source maps for declarations).
Experimental Features: experimentalDecorators (enable decorator support), emitDecoratorMetadata (emit design-time metadata for decorators).
JavaScript Support: allowJs (allow JavaScript files in compilation), checkJs (type check JavaScript files), jsx (JSX support - "preserve", "react", "react-jsx", "react-native").
Linter-like Checks: noUnusedLocals (error on unused local variables), noUnusedParameters (error on unused parameters), noImplicitReturns (error when not all code paths return a value).
Module Interoperability: esModuleInterop (enable emit interoperability between CommonJS and ES Modules), allowSyntheticDefaultImports (allow default imports from modules with no default export).
Incremental Builds: incremental (enable incremental compilation saving .tsbuildinfo files), composite (enable project references), tsBuildInfoFile (specify .tsbuildinfo file location).
Watch & Build: watch (watch files for changes), preserveWatchOutput (clear screen on recompilation), build (build referenced projects).
Command-Line Interface: tsc --init (generate tsconfig.json), tsc --watch (compile in watch mode), tsc --project (specify config file), tsc --showConfig (show resolved configuration).
Best Practices Configuration: Enable strict mode for production, use incremental builds for large projects, configure paths for clean imports, set appropriate target for your environment.
⚙️ TS Config
🎯 Complete Definition
TypeScript Configuration Files (tsconfig.json) define how TypeScript projects are compiled, including which files to include, compiler options, and project references. Understanding tsconfig.json is essential for any TypeScript project.
File Location & Discovery: Typically placed in project root. TypeScript looks for tsconfig.json starting from current directory up to filesystem root. Can use --project flag to specify config file.
Creation & Initialization: Use tsc --init to generate a tsconfig.json with commented options showing all available settings. Can also create manually for custom configurations.
Configuration Structure: JSON file with compilerOptions object, include/exclude arrays (file selection), files array (explicit file list), references array (project references), and extends property (inheritance).
Include/Exclude Patterns: Glob patterns specifying which files to include/exclude from compilation. Default include: **/* if neither include nor files specified. Always exclude node_modules.
Files Array: Explicit list of files to compile (alternative to include/exclude). Useful for small projects or when precise control over compilation unit is needed.
Extends Property: Inherit configuration from another tsconfig.json file. Creates configuration hierarchy. Useful for sharing common settings across multiple projects (monorepos).
References Array: Configure project references for splitting large codebase into smaller, interdependent projects. Each reference has path to another tsconfig.json.
Watch Options: Configuration for watch mode behavior. Can specify which files/directories to watch, polling strategies, and synchronization settings for better performance.
Build Options: incremental and tsBuildInfoFile for incremental compilation (stores build info between compilations). composite enables project references support.
Type Acquisition: typeRoots and types options control automatic type acquisition from @types packages in DefinitelyTyped repository. Can specify custom type declaration locations.
Best Practices: Use extends for base configurations, enable strict mode for production, configure paths for clean imports, use incremental builds for large projects, set appropriate target version.
Environment-Specific Configs: Create separate configurations for development, production, and testing using extends. Each environment can have different optimizations and checks.
Debugging Configuration: Use tsc --showConfig to see resolved configuration, tsc --traceResolution to debug module resolution, and compiler diagnostics flags for performance analysis.
⏳ Async/Await
🎯 Complete Definition
Async/Await is syntactic sugar built on top of Promises in TypeScript/JavaScript, making asynchronous code look and behave more like synchronous code while maintaining non-blocking execution.
Async Functions: Functions declared with async keyword. Always return a Promise. If the function returns a value, the Promise resolves to that value. If the function throws an exception, the Promise rejects with that exception.
Await Expressions: Can only be used inside async functions. Pauses execution of the async function until the Promise settles. Returns the resolved value if the Promise fulfills, throws the rejection reason if the Promise rejects.
Error Handling: Use try/catch blocks with await to handle rejected Promises. Rejected Promises throw exceptions that can be caught synchronously. Alternative: use .catch() on the Promise chain.
Parallel Execution: Use Promise.all() to await multiple promises concurrently (all must succeed). Promise.race() for the first settled promise. Promise.allSettled() for all promises (regardless of success/failure). Promise.any() for first fulfilled promise.
Type Inference: TypeScript infers the Promise return type from async function return value. await expression has the type of the Promise's resolved value (unwrapped).
Promise<T> Type: Generic type representing an asynchronous operation that will eventually produce a value of type T (or never). Essential for typing async operations.
Async Iteration (for await...of): Loop for iterating over async iterables (objects with [Symbol.asyncIterator] method). Used with async generators and streams.
Async Generators (async function*): Functions that can yield multiple values asynchronously. Return AsyncGenerator object. Use yield to produce values, await to consume async operations.
Top-Level Await (TypeScript 3.8+): Support for await at the top level in modules (not in scripts). No need for async wrapper function in module context. Enables module initialization with async operations.
AbortController & AbortSignal: Mechanism for canceling async operations. Pass AbortSignal to abortable APIs like fetch(). Call abort() to cancel ongoing operations.
Error Propagation: Unhandled Promise rejections in async functions propagate to the caller. Use global unhandledrejection event handler to catch unhandled rejections.
Performance Considerations: Each await creates a microtask. Avoid await in tight loops; consider batching operations. Use Promise.all() for independent parallel operations.
Best Practices: Always handle errors, use Promise.all() for parallel independent operations, avoid nesting async functions excessively, use async/await over raw Promise chains for readability.