The typeof Operator

  1. Introduction



  2. Runtime typeof

  3. console.log(typeof 123);       // "number"
    console.log(typeof 'hello');   // "string"
    console.log(typeof true);      // "boolean"
    console.log(typeof {});        // "object"
    console.log(typeof undefined); // "undefined"
    console.log(typeof null);      // "object"  (quirk of JavaScript)
    


  4. Compile-Time typeof (Type Query)

  5. const user = {
        id: 1,
        name: 'Alice',
        active: true
    };
    
    type User = typeof user;
    



  6. Using typeof with Functions
  7. function createPoint(x: number, y: number) {
        return { x, y };
    }
    
    type Point = ReturnType<typeof createPoint>;
    



  8. Using typeof for Constant Union Types
  9. const roles = ['admin', 'user', 'guest'] as const;
    
    type Role = typeof roles[number];
    



  10. typeof with Literal Types
  11. const DEFAULT_PORT = 8080;
    
    type Port = typeof DEFAULT_PORT; // type Port = 8080
    



  12. Using typeof in Type Guards
  13. function logValue(v: string | number) {
        if (typeof v === 'string') {
            console.log(v.toUpperCase());
        } else {
            console.log(v.toFixed(2));
        }
    }
    



  14. Comparison Table

  15. Context Meaning Example
    Runtime Returns a string describing JS type typeof 123 === 'number'
    Compile-Time Returns the TypeScript type of a value type T = typeof x
    Combined Used for safe type narrowing if (typeof v === 'string') ...




The type Operator (Type Aliases)

  1. Introduction



  2. Basic Syntax
  3. type AliasName = ExistingType;
    



  4. Type Alias for Primitive Types
  5. type ID = number;
    type Username = string;
    



  6. Type Alias for Object Types
  7. type User = {
        id: number;
        name: string;
        active: boolean;
    };
    



  8. Function Type Alias
  9. type Add = (a: number, b: number) => number;
    
    const sum: Add = (x, y) => x + y;
    



  10. Union Types with type
  11. type Status = 'success' | 'error' | 'loading';
    
    type StringOrNumber = string | number;
    



  12. Intersection Types
  13. type HasID = { id: number };
    type HasName = { name: string };
    
    type User = HasID & HasName;
    



  14. Intersection with More Types
  15. type HasEmail = { email: string };
    
    type Person = HasID & HasName & HasEmail;
    



  16. Intersection Types with Functions
  17. type CanLog = { log: () => void };
    type CanSave = { save: () => void };
    
    type LoggerSaver = CanLog & CanSave;
    
    const obj: LoggerSaver = {
        log() { console.log("logging"); },
        save() { console.log("saving"); }
    };
    



  18. Merging Object Types (Property Compatibility)
  19. type A = { x: number };
    type B = { x: number | string };
    
    type C = A & B;
    // type C = { x: number } & { x: number | string }
    



  20. Intersection Producing never (Incompatible Types)
  21. type A = { x: string };
    type B = { x: number };
    
    type Impossible = A & B;  // { x: string & number } → never
    



  22. Intersection Types vs Interfaces

  23. interface A { x: number }
    interface B { y: number }
    
    type C = A & B;
    // Equivalent to:
    interface D extends A, B {}
    



  24. Type Aliases for Strings, Numbers, or Enums
  25. type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
    
    type Port = 80 | 443 | 8080;
    



  26. Using typeof with type
  27. const config = {
        host: 'localhost',
        port: 3000
    };
    
    type Config = typeof config;
    



  28. Generic Type Aliases
  29. type Response<T> = {
        data: T;
        error: string | null;
    };
    
    type UserResponse = Response<{ id: number; name: string }>;
    



  30. Mapped Types Using type
  31. type ReadonlyObject<T> = {
        readonly [K in keyof T]: T[K];
    };
    
    type FullUser = { id: number; name: string };
    type ReadonlyUser = ReadonlyObject<FullUser>;
    



  32. Comparison: type vs interface

  33. Feature type interface
    Can define unions Yes No
    Can define primitives Yes No
    Supports declaration merging No Yes
    Mapped types Yes Limited
    Extending others With & With extends





Everyday Types

  1. Primitive Types
  2. let age: number = 25;
    let name: string = "Alice";
    let isActive: boolean = true;
    



  3. Arrays
  4. let numbers: number[] = [1, 2, 3];
    let names: Array<string> = ["Alice", "Bob"];
    



  5. Objects
  6. let user: {
        id: number;
        name: string;
        active: boolean;
    } = {
        id: 1,
        name: "Alice",
        active: true
    };
    



  7. Optional and Readonly Properties
  8. type User = {
        id: number;
        name?: string;              // optional
        readonly active: boolean;   // cannot be modified
    };
    



  9. Functions
  10. function add(a: number, b: number): number {
        return a + b;
    }
    
    const greet = (name: string): void => {
        console.log("Hello " + name);
    };
    



  11. Function Type Aliases
  12. type Add = (x: number, y: number) => number;
    
    const sum: Add = (a, b) => a + b;
    



  13. Union Types
  14. let value: number | string;
    
    value = 42;
    value = "hello";
    



  15. Type Narrowing
  16. function printValue(v: number | string) {
        if (typeof v === "string") {
            console.log(v.toUpperCase());
        } else {
            console.log(v.toFixed(2));
        }
    }
    



  17. Type Aliases
  18. type ID = number;
    type Point = { x: number; y: number; };
    



  19. Interfaces
  20. interface Person {
        id: number;
        name: string;
    }
    



  21. Literal Types
  22. let direction: "left" | "right" | "up" | "down";
    



  23. Nullable Types
  24. let maybe: string | null = null;
    



  25. Enums
  26. enum Status {
        Success,
        Error,
        Loading
    }
    



  27. Tuples
  28. let point: [number, number] = [10, 20];
    



  29. Any, Unknown, and Never
  30. let anything: any;
    let data: unknown;
    function fail(msg: string): never {
        throw new Error(msg);
    }
    





More on Functions

  1. Function Parameter Types
  2. function greet(name: string, age: number): void {
        console.log(`Hello ${name}, age ${age}`);
    }
    



  3. Optional Parameters
  4. function log(message: string, userId?: number) {
        console.log(message, userId ?? "anonymous");
    }
    
    log("Hello");
    log("Hi", 42);
    



  5. Default Parameters
  6. function multiply(a: number, b: number = 1) {
        return a * b;
    }
    
    multiply(5);  // 5
    



  7. Rest Parameters
  8. function sum(...values: number[]): number {
        return values.reduce((a, b) => a + b, 0);
    }
    
    sum(1, 2, 3, 4);
    



  9. Function Return Types
  10. function isEven(n: number): boolean {
        return n % 2 === 0;
    }
    



  11. Anonymous and Arrow Functions
  12. const double = (x: number): number => x * 2;
    
    const logger = function(message: string): void {
        console.log(message);
    };
    



  13. Function Overloads
  14. function format(value: number): string;
    function format(value: string): string;
    function format(value: number | string) {
        return `Value: ${value}`;
    }
    
    format(10);
    format("hello");
    



  15. Function Types
  16. type Comparator = (a: number, b: number) => number;
    
    const compare: Comparator = (x, y) => x - y;
    



  17. Functions as Arguments
  18. function applyOperation(a: number, b: number, op: (x: number, y: number) => number) {
        return op(a, b);
    }
    
    applyOperation(3, 4, (x, y) => x + y);
    



  19. Generic Functions
  20. function identity<T>(value: T): T {
        return value;
    }
    
    const result = identity<string>("hello");
    



  21. Generic Constraints
  22. function getLength<T extends { length: number }>(item: T) {
        return item.length;
    }
    
    getLength("hello");
    getLength([1, 2, 3]);
    



  23. Contextual Typing
  24. const nums = [1, 2, 3];
    
    nums.forEach(n => console.log(n.toFixed(2)));
    



  25. this in Functions
  26. const obj = {
        value: 10,
        getValue() {
            return this.value; // `this` is obj
        }
    };
    



  27. Callable and Constructable Objects
  28. interface Callable {
        (msg: string): void;         // callable
        description: string;         // property
    }
    
    const fn: Callable = (m: string) => console.log(m);
    fn.description = "Logger function";
    



  29. Functions That Return Functions
  30. function createMultiplier(factor: number) {
        return (n: number) => n * factor;
    }
    
    const double = createMultiplier(2);
    





Object Types

  1. Basic Object Types
  2. let user: {
        id: number;
        name: string;
        active: boolean;
    } = {
        id: 1,
        name: "Alice",
        active: true
    };
    



  3. Optional Properties
  4. type User = {
        id: number;
        name?: string;   // optional
    };
    



  5. Readonly Properties
  6. type Config = {
        readonly host: string;
        readonly port: number;
    };
    



  7. Nested Object Types
  8. type Product = {
        id: number;
        details: {
            name: string;
            price: number;
        };
    };
    



  9. Object Types with Methods
  10. type Point = {
        x: number;
        y: number;
        move(dx: number, dy: number): void;
    };
    



  11. Type Aliases for Object Types
  12. type Address = {
        street: string;
        city: string;
        country: string;
    };
    



  13. Intersection-Based Object Composition
  14. type HasID = { id: number };
    type HasName = { name: string };
    
    type User = HasID & HasName;
    



  15. Index Signatures (Dynamic Object Keys)
  16. type Scores = {
        [player: string]: number;
    };
    
    let game: Scores = {
        Alice: 10,
        Bob: 8,
        Charlie: 12
    };
    



  17. Excess Property Checks
  18. type User = { id: number; name: string };
    
    let u: User = {
        id: 1,
        name: "Alice",
        // age: 30   ❌ Error: extra property
    };
    



  19. Using in for Object Type Narrowing
  20. type Fish = { swim: () => void };
    type Bird = { fly: () => void };
    
    function move(animal: Fish | Bird) {
        if ("swim" in animal) {
            animal.swim();
        } else {
            animal.fly();
        }
    }
    



  21. Object Type Compatibility
  22. type Animal = { name: string };
    type Dog = { name: string; bark: () => void };
    
    let a: Animal = { name: "Spike" };
    let d: Dog = { name: "Buddy", bark() {} };
    
    a = d;   // ✔ OK (Dog has at least the properties Animal requires)
    



  23. Readonly vs Mutable Object Types
  24. type MutablePoint = { x: number; y: number };
    type ReadonlyPoint = {
        readonly x: number;
        readonly y: number;
    };
    



  25. "Object" vs "object" vs "{}"

  26. Type Description Example
    object Any non-primitive value {}, [], function() {}
    Object Type of most built-in objects (rarely used) new String("x")
    {} Any non-nullish value 42, "hi", {}





Classes

  1. Basic Class Declaration
  2. class User {
        id: number;
        name: string;
    
        constructor(id: number, name: string) {
            this.id = id;
            this.name = name;
        }
    
        greet() {
            console.log(`Hello, ${this.name}`);
        }
    }
    
    const u = new User(1, "Alice");
    u.greet();
    



  3. Visibility Modifiers
  4. class Person {
        public name: string;   // accessible everywhere
        private age: number;   // accessible inside the class only
        protected id: number;  // accessible inside class + subclasses
    
        constructor(name: string, age: number, id: number) {
            this.name = name;
            this.age = age;
            this.id = id;
        }
    }
    



  5. Read-only Properties
  6. class Config {
        readonly host: string = "localhost";
        readonly port: number;
    
        constructor(port: number) {
            this.port = port;
        }
    }
    



  7. Parameter Properties (Shorthand)
  8. class Point {
        constructor(
            public x: number,
            public y: number
        ) {}
    }
    
    const p = new Point(10, 20);
    



  9. Getters and Setters
  10. class Rectangle {
        constructor(private _width: number, private _height: number) {}
    
        get area() {
            return this._width * this._height;
        }
    
        set width(value: number) {
            if (value <= 0) throw new Error("Invalid width");
            this._width = value;
        }
    }
    



  11. Static Properties and Methods
  12. class MathUtils {
        static PI = 3.14;
    
        static double(n: number) {
            return n * 2;
        }
    }
    
    console.log(MathUtils.PI);
    console.log(MathUtils.double(10));
    



  13. Class Inheritance
  14. class Animal {
        constructor(public name: string) {}
    
        move() {
            console.log(`${this.name} moves`);
        }
    }
    
    class Dog extends Animal {
        bark() {
            console.log("Woof!");
        }
    }
    
    const d = new Dog("Buddy");
    d.move();
    d.bark();
    



  15. Method Overriding
  16. class Base {
        greet() {
            console.log("Hello from Base");
        }
    }
    
    class Derived extends Base {
        override greet() {
            console.log("Hello from Derived");
        }
    }
    



  17. Abstract Classes
  18. abstract class Shape {
        abstract area(): number;
    }
    
    class Circle extends Shape {
        constructor(public radius: number) { super(); }
        area() {
            return Math.PI * this.radius ** 2;
        }
    }
    



  19. Implementing Interfaces
  20. interface Logger {
        log(message: string): void;
    }
    
    class ConsoleLogger implements Logger {
        log(msg: string) {
            console.log(msg);
        }
    }
    



  21. Constructor Type vs Instance Type
  22. class Car {
        constructor(public brand: string) {}
    }
    
    type CarInstance = Car;              // instance type
    type CarConstructor = typeof Car;    // constructor function type
    



  23. Private Fields (# syntax)
  24. class Counter {
        #count = 0;   // hard private, JS-level
    
        increment() {
            this.#count++;
        }
    }
    





Constructor Type vs Instance Type

  1. Introduction



  2. Instance Type
  3. class User {
        constructor(public id: number, public name: string) {}
    }
    
    let u: User = new User(1, "Alice");
    



  4. Constructor Type
  5. type UserConstructor = typeof User;
    



  6. Example: Comparing Both Types
  7. class Car {
        static company = "Tesla";
    
        constructor(public model: string) {}
    }
    
    type CarInstance = Car;             // instance type
    type CarConstructor = typeof Car;   // constructor type
    

    Feature Instance Type (Car) Constructor Type (typeof Car)
    Instance properties ✔ Available ✘ Not available
    Instance methods ✔ Available ✘ Not available
    Static members ✘ Not available ✔ Available
    Constructor signature ✘ No ✔ Yes
    Used with new ✘ No ✔ Yes


  8. Using Constructor Types for Factories
  9. function createInstance(ctor: { new (...args: any[]): any }) {
        return new ctor();
    }
    
    class A { constructor() { console.log("A created"); } }
    class B { constructor() { console.log("B created"); } }
    
    createInstance(A);
    createInstance(B);
    



  10. Typing Class Constructors More Strictly
  11. interface UserConstructor {
        new (id: number, name: string): { id: number; name: string };
    }
    
    function createUser(ctor: UserConstructor) {
        return new ctor(1, "Alice");
    }
    



  12. Static Properties Live on the Constructor Type
  13. class Settings {
        static version = "1.0";
        theme = "light";
    }
    
    let s: Settings = new Settings();   // instance type
    let C: typeof Settings = Settings;  // constructor type
    
    console.log(C.version); // OK
    console.log(s.theme);   // OK
    



  14. Constructor Types and Dependency Injection
  15. function runService(ctor: { new(): Service }) {
        const service = new ctor();
        service.run();
    }
    
    class Service {
        run() { console.log("Running service..."); }
    }
    
    runService(Service);
    



  16. Constructor Types with Generics
  17. function create<T>(ctor: { new (...args: any[]): T }): T {
        return new ctor();
    }
    
    class Logger { log() { console.log("log"); } }
    
    const logger = create(Logger);
    



  18. A Class Is Both a Value and a Type
  19. class Example {}
    
    type T1 = Example;     // instance type
    const T2 = Example;    // constructor value
    



  20. Constructor Type vs Instance Type
  21. class User {
        static role = "user-class";
    
        constructor(public id: number, public name: string) {}
    
        greet() {
            console.log(`Hello, ${this.name}`);
        }
    }
    
    // 1) Instance type: "what new User() returns"
    let instance: User = new User(1, "Alice");
    
    instance.id;        // OK - instance property
    instance.name;      // OK - instance property
    instance.greet();   // OK - instance method
    // instance.role;   // Error: 'role' is static (on the constructor, not instance)
    
    
    // 2) Constructor type: "the class itself (function + statics)"
    let Ctor: typeof User = User;
    
    Ctor.role;                          // OK - static property
    const other = new Ctor(2, "Bob");   // OK - calling the constructor
    
    // other has the instance type:
    other.id;           // OK
    other.greet();      // OK
    
    
    // 3) Using constructor type in a factory
    function createAndGreet(ctor: typeof User, id: number, name: string) {
        const u = new ctor(id, name); // we can 'new' the constructor
        u.greet();
    }
    
    createAndGreet(User, 3, "Charlie");
    





Generics

  1. Introduction



  2. Basic Generic Function
  3. function identity<T>(value: T): T {
        return value;
    }
    
    const a = identity(10);        // T = number
    const b = identity("hello");   // T = string
    



  4. Explicit vs Inferred Type Arguments
  5. identity<number>(123);    // explicit
    identity("hello");        // inferred (T = string)
    



  6. Generic Type Aliases
  7. type Box<T> = {
        value: T;
    };
    
    const numberBox: Box<number> = { value: 42 };
    const stringBox: Box<string> = { value: "hi" };
    



  8. Generic Interfaces
  9. interface Repository<T> {
        findById(id: number): T | null;
        save(entity: T): void;
    }
    
    type User = { id: number; name: string };
    
    const userRepo: Repository<User> = {
        findById(id) {
            return { id, name: "Alice" };
        },
        save(user) {
            console.log("Saving", user.name);
        }
    };
    



  10. Generic Classes
  11. class Stack<T> {
        private items: T[] = [];
    
        push(item: T) {
            this.items.push(item);
        }
    
        pop(): T | undefined {
            return this.items.pop();
        }
    }
    
    const numStack = new Stack<number>();
    numStack.push(1);
    numStack.push(2);
    
    const strStack = new Stack<string>();
    strStack.push("a");
    strStack.push("b");
    



  12. Constrained Generics with extends
  13. function getLength<T extends { length: number }>(value: T): number {
        return value.length;
    }
    
    getLength("hello");         // ✔ string has length
    getLength([1, 2, 3]);       // ✔ array has length
    // getLength(123);          // ❌ number has no length
    



  14. Keyof and Indexed Access with Generics
  15. type User = {
        id: number;
        name: string;
    };
    
    type UserKey = keyof User;              // "id" | "name"
    
    function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
        return obj[key];
    }
    
    const u: User = { id: 1, name: "Alice" };
    
    const idValue = getProp(u, "id");
    const nameValue = getProp(u, "name");
    // getProp(u, "age");                   // ❌ Error: "age" not in "id" | "name"
    



  16. Default Type Parameters
  17. type ApiResponse<T = unknown> = {
        data: T;
        error: string | null;
    };
    
    const r1: ApiResponse = {
        data: 123,          // T = unknown, but still typed
        error: null
    };
    
    const r2: ApiResponse<{ id: number }> = {
        data: { id: 1 },
        error: null
    };
    



  18. Generic Utility Types (Built-in)
  19. type User = {
        id: number;
        name: string;
        email?: string;
    };
    
    type ReadonlyUser = Readonly<User>;
    type PartialUser = Partial<User>;
    type UserWithoutEmail = Omit<User, "email">;
    



  20. Generics with Arrays and Promises
  21. let nums: Array<number> = [1, 2, 3];
    
    function fetchUser(): Promise<{ id: number; name: string }> {
        return Promise.resolve({ id: 1, name: "Alice" });
    }
    



  22. Generic Constraints with Multiple Parameters
  23. function merge<A extends object, B extends object>(a: A, b: B): A & B {
        return { ...a, ...b };
    }
    
    const merged = merge(
        { id: 1, name: "Alice" },
        { active: true }
    );
    // type of merged: { id: number; name: string } & { active: boolean }
    



  24. Generic "Shape-Preserving" Functions
  25. function mapValues<T, U>(
        obj: T,
        fn: (value: T[keyof T]) => U
    ): { [K in keyof T]: U } {
        const result: any = {};
        for (const key in obj) {
            result[key] = fn(obj[key]);
        }
        return result;
    }
    
    const original = { a: 1, b: 2, c: 3 };
    const doubled = mapValues(original, v => v * 2);
    // type of doubled: { a: number; b: number; c: number }
    



  26. When to Use Generics

  27. Situation Example Why Generics?
    Reusable container Stack<T>, Box<T> Same logic for many element types
    Reusable API Repository<T> One interface for many domain models
    Transforming types Readonly<T>, Partial<T> Programmatic type manipulation
    Safe property access getProp<T, K>(obj, key) Prevent typos and invalid keys





The keyof Type Operator

  1. Introduction



  2. Basic Usage with Object Types
  3. type User = {
        id: number;
        name: string;
        active: boolean;
    };
    
    type UserKeys = keyof User;
    // type UserKeys = "id" | "name" | "active"
    



  4. Using keyof to Type-Safe Property Access
  5. type User = {
        id: number;
        name: string;
    };
    
    function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
        return obj[key];
    }
    
    const u: User = { id: 1, name: "Alice" };
    
    const id = getProp(u, "id");      // type: number
    const name = getProp(u, "name");  // type: string
    // getProp(u, "age");             // ❌ Error: "age" not in "id" | "name"
    



  6. keyof with Index Signatures
  7. type Scores = {
        [player: string]: number;
    };
    
    type ScoreKey = keyof Scores;
    // type ScoreKey = string | number
    



  8. keyof with Arrays and Tuples
  9. type Numbers = number[];
    
    type NumbersKey = keyof Numbers;
    // type NumbersKey = number | "length" | "push" | "pop" | ...
    
    type Point = [number, number];
    
    type PointKey = keyof Point;
    // type PointKey = "0" | "1" | "length" | ...
    



  10. keyof and Unions of Object Types
  11. type Cat = { meow: () => void; name: string };
    type Dog = { bark: () => void; name: string };
    
    type Pet = Cat | Dog;
    type PetKeys = keyof Pet;
    // type PetKeys = "name"  | "meow" | "bark"
    



  12. keyof and Intersections
  13. type A = { id: number; name: string };
    type B = { name: string; active: boolean };
    
    type AB = A & B;
    type ABKeys = keyof AB;
    // type ABKeys = "id" | "name" | "active"
    



  14. keyof Special Cases: any and never
  15. type KAny = keyof any;      // string | number | symbol
    type KNever = keyof never;  // never
    



  16. Combining keyof with Indexed Access Types
  17. type User = {
        id: number;
        name: string;
        active: boolean;
    };
    
    type UserKey = keyof User;    // "id" | "name" | "active"
    type UserValue = User[UserKey];
    // type UserValue = number | string | boolean
    



  18. Building Utility Types with keyof
  19. type User = {
        id: number;
        name: string;
        email?: string;
    };
    
    type PickProps<T, K extends keyof T> = {
        [P in K]: T[P];
    };
    
    type UserBasic = PickProps<User, "id" | "name">;
    // type UserBasic = { id: number; name: string; }
    



  20. Using keyof to Constrain APIs
  21. type Settings = {
        theme: "light" | "dark";
        language: "en" | "de";
        pageSize: number;
    };
    
    function updateSetting<K extends keyof Settings>(
        key: K,
        value: Settings[K]
    ) {
        // ...
    }
    
    updateSetting("theme", "dark");         // ✔ OK
    updateSetting("pageSize", 20);          // ✔ OK
    // updateSetting("language", "fr");     // ❌ Error: "fr" not assignable to "en" | "de"
    




Indexed Access Types (T[K])

  1. Indexed access types let you look up the type of a property by its key, using the syntax T[K].


  2. You can think of T as an object type, and K as a property name (or union of names).


  3. Indexed access types are pure type-level operations, they do not exist at runtime.


  4. Basic Example: Single Property
  5. type User = {
        id: number;
        name: string;
        active: boolean;
    };
    
    type UserIdType = User["id"];       // number
    type UserNameType = User["name"];   // string
    


  6. Using Unions as Index Keys
  7. type User = {
        id: number;
        name: string;
        active: boolean;
    };
    
    type IdOrName = User["id" | "name"];    // number | string
    


  8. Combining with keyof: All Property Values
  9. type User = {
        id: number;
        name: string;
        active: boolean;
    };
    
    type UserKey = keyof User;          // "id" | "name" | "active"
    type UserValue = User[UserKey];     // number | string | boolean
    


  10. Working with Arrays and Tuples
  11. type Numbers = number[];
    
    type Element = Numbers[number];
    // type Element = number
    
    type Point = [number, number, number];
    
    type PointIndex = keyof Point;
    // type PointIndex = "0" | "1" | "2" | "length" | ...
    
    type PointElement = Point[number];
    // type PointElement = number
    



  12. Nested Indexed Access
  13. type Product = {
        id: number;
        details: {
            name: string;
            price: number;
        };
    };
    
    type ProductDetails = Product["details"];
    // { name: string; price: number; }
    
    type ProductPrice = Product["details"]["price"];
    // number
    



  14. Indexed Access with Generics
  15. type GetPropType<T, K extends keyof T> = T[K];
    
    type User = {
        id: number;
        name: string;
    };
    
    type UserIdType   = GetPropType<User, "id">;   // number
    type UserNameType = GetPropType<User, "name">; // string
    


  16. Shape-Preserving Functions with T[K]
  17. function pluck<T, K extends keyof T>(obj: T, keys: K[]): T[K][] {
        return keys.map(k => obj[k]);
    }
    
    type User = {
        id: number;
        name: string;
        active: boolean;
    };
    
    const u: User = { id: 1, name: "Alice", active: true };
    
    const values = pluck(u, ["id", "name"]);
    // type of values: (number | string)[]
    



  18. Using Indexed Access in Utility Types
  19. type PickProps<T, K extends keyof T> = {
        [P in K]: T[P];
    };
    
    type User = {
        id: number;
        name: string;
        email: string;
    };
    
    type BasicUser = PickProps<User, "id" | "name">;
    // { id: number; name: string; }
    



  20. Extracting the Type of a Method
  21. type Service = {
        start(): void;
        stop(code: number): void;
    };
    
    type StartType = Service["start"];    // () => void
    type StopType = Service["stop"];      // (code: number) => void
    



  22. Value Type of a Dictionary
  23. type Dictionary = Record<string, number>;
    
    type DictValue = Dictionary[string];
    // type DictValue = number
    



  24. Indexed Access and Readonly Transformations
  25. type ReadonlyObject<T> = {
        readonly [K in keyof T]: T[K];
    };
    
    type User = {
        id: number;
        name: string;
    };
    
    type ReadonlyUser = ReadonlyObject<User>;
    // { readonly id: number; readonly name: string; }
    



  26. Index Signatures for Dynamic String Keys

  27. type StringMap = {
        // NOTE: the name `key` here is arbitrary, you can use any identifiers here.
        [key: string]: string;
    };
    
    const m: StringMap = {
        "user name": "Alice",
        "user-email": "a@example.com",
    };
    
    const a = m["user name"];   // string
    const b = m["user-email"];  // string
    // const c = m["age"];      // string | undefined (runtime)
    





Conditional Types

  1. Conditional types allow TypeScript to express logic inside the type system.


  2. The syntax resembles a JavaScript ternary, but applies entirely at compile time:
  3. T extends U ? X : Y
    It means: "If T is assignable to U, then the resulting type is X, otherwise Y."



  4. Basic Syntax
  5. type IsString<T> = T extends string ? "yes" : "no";
    
    type A = IsString<string>;   // "yes"
    type B = IsString<number>;   // "no"
    



  6. Conditional Types with Generics
  7. type Boxed<T> =
        T extends number ? { value: number } :
        T extends string ? { value: string } :
        { value: T };
    
    type X = Boxed<number>;   // { value: number }
    type Y = Boxed<string>;   // { value: string }
    type Z = Boxed<boolean>;  // { value: boolean }
    



  8. Distributive Conditional Types

  9. type ToArray<T> = T extends any ? T[] : never;
    
    type A = ToArray<string | number>;
    // A = string[] | number[]
    



  10. Filtering Unions
  11. type ExtractString<T> = T extends string ? T : never;
    
    type R = ExtractString<string | number | boolean>;
    // R = string
    



  12. Excluding Types
  13. type ExcludeNumber<T> = T extends number ? never : T;
    
    type R = ExcludeNumber<string | number | boolean>;
    // R = string | boolean
    



  14. Inferring Types Using infer

  15. type ReturnTypeOf<T> =
        T extends (...args: any[]) => infer R
            ? R
            : never;
    
    function foo() {
        return { id: 1, name: "Alice" };
    }
    
    type R = ReturnTypeOf<typeof foo>;
    // { id: number; name: string }
    



  16. Inferring Tuple and Array Element Types
  17. type ElementOf<T> =
        T extends (infer U)[] ? U : never;
    
    type A = ElementOf<string[]>;   // string
    type B = ElementOf<number[]>;   // number
    



  18. Inferring Function Parameters
  19. type FirstArg<T> =
        T extends (arg: infer A, ...rest: any[]) => any
            ? A
            : never;
    
    type F = FirstArg<(x: number, y: string) => void>;
    // number
    



  20. Conditional Types with readonly and Mutability Checks
  21. type IsReadonlyArray<T> = T extends readonly any[] ? true : false;
    
    type A = IsReadonlyArray<readonly number[]>;   // true
    type B = IsReadonlyArray<number[]>;            // false
    



  22. Real-World Example: Extracting a Promise's Resolved Type
  23. type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
    
    type A = UnwrapPromise<Promise<number>>;     // number
    type B = UnwrapPromise<Promise<string>>;     // string
    type C = UnwrapPromise<number>;              // number
    



  24. Real-World Example: JSON Serialization Type
  25. type JsonSafe<T> =
        T extends string | number | boolean | null
            ? T
            : T extends (infer U)[]
                ? JsonSafe<U>[]
                : T extends object
                    ? { [K in keyof T]: JsonSafe<T[K]> }
                    : never;
    
    type User = {
        id: number;
        name: string;
        flags: boolean[];
    };
    
    type J = JsonSafe<User>;
    // {
    //   id: number;
    //   name: string;
    //   flags: boolean[];
    // }
    



  26. Summary Table

  27. Feature Purpose Example
    Basic condition Choose between two types T extends U ? A : B
    Distributive behavior Map each union member (A | B) extends X ? Y : Z
    infer keyword Extract parts of a type infer R
    Filtering unions Keep or remove union members string | never
    Recursive conditional types Transform deep structures JSON-safe types




Mapped Types

  1. Introduction



  2. Basic Example
  3. type User = {
        id: number;
        name: string;
    };
    
    type OptionalUser = {
        [K in keyof User]?: User[K];
    };
    // { id?: number; name?: string }
    



  4. Readonly Mapped Types
  5. type ReadonlyObject<T> = {
        readonly [K in keyof T]: T[K];
    };
    
    type Product = {
        price: number;
        title: string;
    };
    
    type ReadonlyProduct = ReadonlyObject<Product>;
    // { readonly price: number; readonly title: string }
    



  6. Adding, Removing and Changing Modifiers

  7. type Mutable<T> = {
        -readonly [K in keyof T]: T[K];
    };
    
    type RequiredObject<T> = {
        [K in keyof T]-?: T[K];
    };
    
    type OptionalObject<T> = {
        [K in keyof T]?: T[K];
    };
    



  8. Remapping Keys with as

  9. type PrefixKeys<T> = {
        [K in keyof T as `prefix_${K}`]: T[K];
    };
    
    type Example = {
        a: number;
        b: string;
    };
    
    type WithPrefix = PrefixKeys<Example>;
    // { prefix_a: number; prefix_b: string }
    



  10. Filtering Keys

  11. type RemoveMethods<T> = {
        [K in keyof T as T[K] extends Function ? never : K]: T[K];
    };
    
    type Model = {
        id: number;
        save(): void;
        load(): void;
    };
    
    type DataOnly = RemoveMethods<Model>;
    // { id: number }
    



  12. Mapping Over Unions

  13. type EventName = "click" | "focus" | "keydown";
    
    type EventMap = {
        [E in EventName]: { type: E };
    };
    
    type M = EventMap;
    // {
    //   click:   { type: "click" },
    //   focus:   { type: "focus" },
    //   keydown: { type: "keydown" }
    // }
    



  14. Mapping and Transforming Value Types

  15. type Nullable<T> = {
        [K in keyof T]: T[K] | null;
    };
    
    type User = {
        id: number;
        name: string;
    };
    
    type NullableUser = Nullable<User>;
    // { id: number | null; name: string | null }
    



  16. Mapped Types Combined with Conditional Types

  17. type Serialize<T> = {
        [K in keyof T]: T[K] extends Function
            ? never
            : T[K] extends object
                ? Serialize<T[K]>
                : T[K];
    };
    
    type Model = {
        id: number;
        flags: { admin: boolean };
        save(): void;
    };
    
    type S = Serialize<Model>;
    // { id: number; flags: { admin: boolean } }
    



  18. Constructing Dictionary Types
  19. type Dictionary<K extends string, V> = {
        [P in K]: V;
    };
    
    type UserRoles = Dictionary<"admin" | "user" | "guest", boolean>;
    // { admin: boolean; user: boolean; guest: boolean }
    



  20. Built-In Mapped Type Utilities

  21. type Partial<T> = {
        [K in keyof T]?: T[K];
    };
    
    type Required<T> = {
        [K in keyof T]-?: T[K];
    };
    
    type Readonly<T> = {
        readonly [K in keyof T]: T[K];
    };
    
    type Record<K extends string, T> = {
        [P in K]: T;
    };
    



  22. Summary

  23. Concept Explanation Example
    Key iteration Iterate over keys with keyof [K in keyof T]
    Property copying Reusing existing types T[K]
    Modifier changes Add/remove readonly / ? +readonly, -?
    Key remapping Rename or filter keys as ...
    Union mapping Build objects from unions [K in "a" | "b"]




The infer Keyword

  1. infer is a special keyword used inside conditional types to extract some part of a type and assign it to a new type variable.


  2. You can think of infer as "pattern matching for types": if the pattern fits, TypeScript extracts the needed portion.


  3. infer only works inside conditional types of the form:
  4. T extends SomePattern<infer X> ? Result : Fallback


  5. Basic Example: Extracting a Function's Return Type
  6. type ReturnTypeOf<T> =
        T extends (...args: any[]) => infer R
            ? R
            : never;
    
    function foo() {
        return { id: 1, name: "Alice" };
    }
    
    type R = ReturnTypeOf<typeof foo>;
    // { id: number; name: string }
    



  7. Extracting Function Parameter Types
  8. type FirstArg<T> =
        T extends (arg: infer A, ...rest: any[]) => any
            ? A
            : never;
    
    type X = FirstArg<(x: number, y: string) => void>;
    // number
    



  9. Extracting Tuple and Array Element Types
  10. type ElementOf<T> =
        T extends (infer U)[] ? U : never;
    
    type A = ElementOf<string[]>;  // string
    type B = ElementOf<number[]>;  // number
    



  11. Extracting Tuple Element Types With Precision
  12. type TupleFirst<T> =
        T extends [infer A, ...any[]] ? A : never;
    
    type TupleRest<T> =
        T extends [any, ...infer R] ? R : never;
    
    type T1 = TupleFirst<[1, 2, 3]>;   // 1
    type T2 = TupleRest<[1, 2, 3]>;    // [2, 3]
    



  13. Extracting the Resolved Type of a Promise
  14. type UnwrapPromise<T> =
        T extends Promise<infer U> ? U : T;
    
    type P1 = UnwrapPromise<Promise<string>>;  // string
    type P2 = UnwrapPromise<Promise<number>>;  // number
    type P3 = UnwrapPromise<number>;           // number
    



  15. Extracting Object Property Types
  16. type ValueOf<T> =
        T extends { [K: string]: infer V } ? V : never;
    
    type Obj = { a: number; b: string; };
    
    type V = ValueOf<Obj>;
    // number | string
    



  17. Extracting Constructor Instance Types
  18. type InstanceTypeOf<T> =
        T extends new (...args: any[]) => infer R
            ? R
            : never;
    
    class User {
        constructor(public id: number) {}
    }
    
    type U = InstanceTypeOf<typeof User>;
    // User
    



  19. Inferring Within Nested Structures
  20. type ResponseType<T> =
        T extends { data: infer D } ? D : never;
    
    type Api = {
        data: {
            id: number;
            name: string;
        }
    };
    
    type R = ResponseType<Api>;
    // { id: number; name: string }
    



  21. Combining infer with Conditional Mapped Types
  22. type DeepUnwrapPromise<T> = {
        [K in keyof T]: T[K] extends Promise<infer U>
            ? U
            : T[K];
    };
    
    type Obj = {
        name: string;
        age: Promise<number>;
    };
    
    type NewObj = DeepUnwrapPromise<Obj>;
    // { name: string; age: number }
    



  23. Recursive Extraction with infer
  24. type DeepResolve<T> =
        T extends Promise<infer U>
            ? DeepResolve<U>
            : T;
    
    type P = DeepResolve<Promise<Promise<string>>>;
    // string
    



  25. Using infer to Detect Arrays vs Non-Arrays
  26. type IsArray<T> =
        T extends readonly any[] ? true : false;
    
    type A = IsArray<number[]>;             // true
    type B = IsArray<readonly string[]>;    // true
    type C = IsArray<number>;               // false
    



  27. Summary Table

  28. Pattern Purpose Example
    infer R in function patterns Extract return type or parameter type (...args) => infer R
    infer U in array patterns Extract element type (infer U)[]
    infer A in tuple patterns Extract first, last, or rest elements [infer A, ...rest]
    Nested infer Deep extraction inside objects { data: infer D }
    Recursive infer Unwrap nested structures Promise<Promise<...>>




Template Literal Types

  1. Introduction



  2. Basic Template Literal Type
  3. type Greeting = `Hello ${string}`;
    
    let a: Greeting = "Hello Alice";  // OK
    let b: Greeting = "Hi Bob";       // Error
    



  4. Using Union Types Inside Template Literals
  5. type Direction = "up" | "down";
    type Move = `move-${Direction}`;
    
    let a: Move = "move-up";    // OK
    let b: Move = "move-left";  // Error
    



  6. Combining Multiple Unions
  7. type Size = "small" | "medium" | "large";
    type Color = "red" | "blue";
    
    type Variant = `${Size}-${Color}`;
    
    let v1: Variant = "small-red";      // OK
    let v2: Variant = "large-blue";     // OK
    let v3: Variant = "medium-green";   // Error
    



  8. Inferring Template Literal Types
  9. function makeEvent(name: string) {
        return `on-${name}` as const;
    }
    
    const e = makeEvent("click");
    // type: "on-click"
    



  10. Narrowing With Template Literal Types
  11. type ID = `id-${number}`;
    
    function printID(id: ID) {
        console.log(id);
    }
    
    printID("id-42");     // OK
    printID("id-Alice");  // Error
    



  12. Template Literal Types With Built-In String Manipulation Types
  13. type Name = "alice" | "bob";
    type Capitalized = Capitalize<Name>;
    
    type Greeting = `Hello ${Capitalized}`;
    
    let a: Greeting = "Hello Alice"; // OK
    let b: Greeting = "Hello bob";   // Error
    



  14. Building Safe API Routes With Template Literal Types
  15. type UserID = number;
    type Route = `/users/${UserID}/posts/${number}`;
    
    let r: Route = "/users/12/posts/99"; // OK
    let x: Route = "/users/A/posts/5";   // Error
    



  16. Extracting Parts Using Inference
  17. type Event = `on-${string}`;
    
    function handle<T extends Event>(name: T) {
        const type = name.replace("on-", "");
        return type;
    }
    
    handle("on-click"); // OK
    handle("on-move");  // OK
    handle("click");    // Error
    



  18. Template Literals in Conditional Types
  19. type RemovePrefix<T> = T extends `id-${infer U}` ? U : never;
    
    type R1 = RemovePrefix<"id-123">; // "123"
    type R2 = RemovePrefix<"user">;   // never
    



  20. Tagging and Branding Types
  21. type BrandedID = `${number}-user-id`;
    
    let id1: BrandedID = "123-user-id"; // OK
    let id2: BrandedID = "123abc";      // Error
    



  22. Summary of Template Literal Types

  23. Feature Description Example
    Basic construction Create string patterns using ${} `Hello ${string}`
    Union expansion Build combinations from unions `move-${"left"|"right"}`
    Type-safe strings Prevent invalid formats id-${number}
    Integration with utility types Uppercase, Lowercase, Capitalize `Hello ${Capitalize<T>}`
    Pattern inference Extract inner substrings with infer T extends `x-${infer U}`
    API schemas Build strict REST endpoints `/users/${number}`




Modules in TypeScript

  1. Introduction



  2. Named Exports
  3. // math.ts
    export const PI = 3.14;
    export function add(a: number, b: number) {
        return a + b;
    }
    

    import { PI, add } from "./math";
    


  4. Renaming Exports and Imports to Avoid Conflicts or for Clarity
  5. // utils.ts
    export function calculate() {}
    
    import { calculate as calc } from "./utils";
    calc();
    


  6. Default Exports
  7. // greet.ts
    export default function greet(name: string) {
        return `Hello ${name}`;
    }
    
    import greet from "./greet";
    greet("Alice");
    



  8. Mixing Default and Named Exports
  9. // server.ts
    export default function connect() {}
    export const PORT = 8080;
    
    import connect, { PORT } from "./server";
    



  10. Re-exporting
  11. // math.ts
    export const PI = 3.14;
    export const E = 2.718;
    
    // constants.ts
    export * from "./math";
    
    import { PI } from "./constants";
    



  12. Re-exporting with Renaming
  13. export { PI as PI_VALUE } from "./math";
    



  14. Importing Everything
  15. import * as utils from "./utils";
    
    utils.log("Hello");
    utils.debug("Test");
    



  16. Type-Only Imports and Exports
  17. export type User = {
        id: number;
        name: string;
    };
    
    import type { User } from "./types";
    
    let u: User = { id: 1, name: "Alice" };
    



  18. Type-Only Re-exports
  19. export type { User } from "./types";
    



  20. ES Modules vs CommonJS (in Node)



  21. export = and import = require() (CommonJS interoperability)
  22. const fs = require("fs");
    export = fs;
    
    import fs = require("fs");
    



  23. Barrel Files (Index Files)
  24. // index.ts
    export * from "./math";
    export * from "./utils";
    export * from "./types";
    
    import { add, PI, User } from "./index";
    



  25. Summary of Modules in TypeScript

  26. Feature Usage Example
    Named exports Export multiple items export const x = 1;
    Default export One main export per module export default fn;
    Namespace import Group all exports import * as A from "./a"
    Type-only imports Avoid emitting JS import type { T }
    Re-exporting Forward exports export * from "./a"
    Barrel files Centralized exports index.ts




Decorators in TypeScript

  1. Introduction



  2. Decorator Basics
  3. function SimpleDecorator(constructor: Function) {
        console.log("Decorated:", constructor.name);
    }
    
    @SimpleDecorator
    class MyClass {}
    



  4. Class Decorators

  5. function LogClass(target: Function) {
        console.log(`Class: ${target.name}`);
    }
    
    @LogClass
    class User {}
    



  6. Class Decorator Factory
  7. function WithRole(role: string) {
        return function (target: Function) {
            target.prototype.role = role;
        };
    }
    
    @WithRole("admin")
    class Account {}
    
    const a = new Account();
    console.log(a.role);        // "admin"
    



  8. Method Decorators

  9. function LogMethod(target: any, key: string, descriptor: PropertyDescriptor) {
        const original = descriptor.value;
    
        descriptor.value = function (...args: any[]) {
            console.log(`Calling ${key} with`, args);
            return original.apply(this, args);
        };
    }
    
    class Calculator {
        @LogMethod
        add(a: number, b: number) {
            return a + b;
        }
    }
    
    const c = new Calculator();
    c.add(2, 3);
    



  10. Accessor Decorators
  11. function Readonly(target: any, key: string, descriptor: PropertyDescriptor) {
        descriptor.writable = false;
    }
    
    class Person {
        private _name = "Alice";
    
        @Readonly
        get name() {
            return this._name;
        }
    }
    
    // person.name = "Bob"; // Error
    



  12. Property Decorators

  13. function Required(target: any, key: string) {
        console.log(`${key} is required`);
    }
    
    class Settings {
        @Required
        theme!: string;
    }
    



  14. Parameter Decorators
  15. function LogParam(target: any, key: string, index: number) {
        console.log(`Parameter #${index} in ${key}`);
    }
    
    class Service {
        greet(@LogParam name: string) {
            console.log("Hello " + name);
        }
    }
    



  16. Using Decorators for Dependency Injection
  17. function Inject(service: any) {
        return function (target: any, key: string, index: number) {
            console.log(`Injecting ${service.name} into ${key}`);
        };
    }
    
    class Logger {}
    
    class Controller {
        constructor(@Inject(Logger) private logger: Logger) {}
    }
    



  18. Metadata Decorators
  19. import "reflect-metadata";
    
    function Type(type: any) {
        return function (target: any, key: string) {
            Reflect.defineMetadata("design:type", type, target, key);
        };
    }
    
    class Box {
        @Type(String)
        content!: string;
    }
    
    const type = Reflect.getMetadata("design:type", new Box(), "content");
    console.log(type.name); // "String"
    



  20. Execution Order of Decorators

  21. function A() { return () => console.log("A"); }
    function B() { return () => console.log("B"); }
    
    @A()
    @B()
    class Example {}
    



  22. Summary of Decorators in TypeScript

  23. Decorator Type Purpose Arguments Received
    Class Decorator Modify/replace class constructor (constructor)
    Method Decorator Modify method behavior (target, key, descriptor)
    Accessor Decorator Control getters/setters (target, key, descriptor)
    Property Decorator Attach metadata to fields (target, key)
    Parameter Decorator Inject or annotate parameters (target, key, index)




Getters and Setters in TypeScript

  1. Introduction



  2. Basic Example of Getter and Setter
  3. class User {
        private _name: string = "";
    
        get name() {
            return this._name.toUpperCase();
        }
    
        set name(value: string) {
            if (value.length < 2) {
                throw new Error("Name too short");
            }
            this._name = value;
        }
    }
    
    const u = new User();
    u.name = "alice";          // calls the setter
    console.log(u.name);       // calls the getter
    



  4. Why Not Just Use Methods?
  5. u.getName();       // explicit method
    u.setName("Bob");  // explicit method
    



  6. Getter Only (Read-Only Property)
  7. class Circle {
        constructor(private radius: number) {}
    
        get area() {
            return Math.PI * this.radius * this.radius;
        }
    }
    
    const c = new Circle(10);
    console.log(c.area);  // computed every time
    



  8. Setter Only (Write-Only Property)
  9. class Logger {
        set message(value: string) {
            console.log("Log:", value);
        }
    }
    
    const log = new Logger();
    log.message = "Hello";  // allowed
    // console.log(log.message); // ERROR: getter missing
    



  10. Using Getters and Setters to Control Access
  11. class Person {
        private _age = 0;
    
        get age() {
            return this._age;
        }
    
        set age(value: number) {
            if (value < 0 || value > 150) {
                throw new Error("Invalid age");
            }
            this._age = value;
        }
    }
    



  12. Getters and Setters with Types
  13. class Point {
        private _x = 0;
    
        get x(): number {
            return this._x;
        }
    
        set x(value: number) {
            this._x = value;
        }
    }
    



  14. How They Work Internally (Property Descriptor)

  15. Object.defineProperty(Person.prototype, "age", {
        get: function () { ... },
        set: function (value) { ... },
        enumerable: true,
        configurable: true
    });
    



  16. Getters and Setters with Private Fields
  17. class Account {
        #balance = 0;
    
        get balance() {
            return this.#balance;
        }
    
        set balance(value: number) {
            if (value < 0) throw new Error("Negative balance not allowed");
            this.#balance = value;
        }
    }
    



  18. Getters and Setters with Computation
  19. class Temperature {
        constructor(private celsius: number) {}
    
        get fahrenheit() {
            return this.celsius * 1.8 + 32;
        }
    
        set fahrenheit(value: number) {
            this.celsius = (value - 32) / 1.8;
        }
    }
    



  20. Combining Getters, Setters, and Decorators
  21. function Log(target: any, key: string, descriptor: PropertyDescriptor) {
        const originalSet = descriptor.set!;
        descriptor.set = function (value: any) {
            console.log(`Assigning ${key} =`, value);
            originalSet.call(this, value);
        };
    }
    
    class Product {
        private _price = 0;
    
        @Log
        set price(value: number) {
            this._price = value;
        }
    
        get price() {
            return this._price;
        }
    }
    



  22. Summary of Getters and Setters in TypeScript

  23. Feature Description Example
    Getter Runs when accessing a property obj.name
    Setter Runs when assigning to a property obj.name = value
    Computed property Looks like a field but acts like a function get area() {...}
    Validation Prevent invalid values set age(v)
    Encapsulation Hide private data #balance
    Interoperability Works well with decorators and metadata @Log on setter




TypeScript Record

  1. Introduction



  2. Basic Example

  3. const scores: Record<string, number> = {
        math: 90,
        physics: 85,
        english: 88
    };


  4. Using Literal Types as Keys

  5. type Theme = "light" | "dark" | "solarized"
    
    const options: Record<Theme, boolean> = {
        light: true,
        dark: false,
        solarized: true
    }


  6. Using Record for Lookup Tables

  7. const handlers: Record<string, () => void> = {
        save: () => console.log("saving..."),
        load: () => console.log("loading..."),
    };


  8. Record with Index Signatures

  9. // Equivalent:
    type A = Record<string, number>
    
    // Same as:
    type B = {
        [key: string]: number
    }


  10. Record with Number Keys

  11. const points: Record<number, string> = {
        1: "one",
        2: "two",
        3: "three"
    }


  12. Record with Complex Value Types

  13. interface User {
        id: number
        name: string
    }
    
    const users: Record<number, User> = {
        1: { id: 1, name: "Alice" },
        2: { id: 2, name: "Bob" }
    }


  14. Record with Enum Keys

  15. enum Status {
        Pending = "pending",
        Approved = "approved",
        Rejected = "rejected"
    }
    
    const statusText: Record<Status, string> = {
        [Status.Pending]: "Waiting...",
        [Status.Approved]: "Approved ✓",
        [Status.Rejected]: "Rejected ✗"
    }


  16. Using Partial Record

  17. type Language = "en" | "de" | "fr"
    
    const labels: Partial<Record<Language, string>> = {
        en: "Hello",
        de: "Hallo"
        // "fr" is optional now
    }


  18. Record vs Map

  19. Use Case Record Map
    Type-checked lookup table ✓ Ideal OK
    Runtime dynamic keys Not ideal ✓ Best choice
    Iteration performance Fast A bit slower
    Keeps insertion order Yes (in JS) Yes



  20. Summary

  21. Concept Description
    Record<K, V> Create an object with keys K and values V
    Keys Can be strings, numbers, enums, or unions
    Values Any valid TypeScript type
    Type safety Ensures correct keys and values
    Best usage Maps, dictionaries, configuration objects



Understanding .d.ts Files in TypeScript (Beginner-Friendly, Very Detailed)

  1. What Is a .d.ts File?



  2. Why Do We Need It?



  3. Two Kinds of Declaration Files

    1. Library declaration files

    2. Global/project declaration files


  4. What Goes Inside a .d.ts File?

  5. declare function greet(name: string): void;
    
    declare const version: string;
    
    declare interface User {
        id: number;
        name: string;
    }
    


  6. Declaration Files for Modules

  7. declare module "my-library" {
        export function doSomething(a: number): void;
        export const version: string;
    }
    


  8. Global Declarations (No import needed)

  9. declare global {
        interface Window {
            myGlobalVar: string;
        }
    }
    
    window.myGlobalVar = "hello!";
    


  10. Extending Existing Types (Augmentation)

  11. declare module "vue" {
        interface ComponentCustomProperties {
            $log: (msg: string) => void;
        }
    }
    


  12. How TypeScript Finds .d.ts Files

  13. src/types/*.d.ts
    

    "include": [
      "src/**/*",
      "src/types/**/*.d.ts"
    ]
    


  14. Writing Declaration Files for JavaScript Code

  15. // utils.js
    export function sum(a, b) {
        return a + b;
    }
    
    // utils.d.ts
    export function sum(a: number, b: number): number;
    


  16. Example: Making a Global Vue Property Work

  17. app.config.globalProperties.$toast = (msg: string) => alert(msg);
    declare module "vue" {
        interface ComponentCustomProperties {
            $toast: (msg: string) => void;
        }
    }