Skip to content

Latest commit

 

History

History
1513 lines (1253 loc) · 76.1 KB

File metadata and controls

1513 lines (1253 loc) · 76.1 KB

Module 24 — Master Cheat Sheet: TypeScript → Python Ultimate Reference

This is the definitive, consolidated cheat sheet for every TypeScript developer learning or working with Python. Every major concept from all previous modules is merged here with side-by-side comparisons, visual charts, decision trees, time complexity tables, Mermaid diagrams, and quick-reference guides. Use this as your go-to reference when writing Python code.


Table of Contents


1. At-a-Glance: TypeScript ↔ Python Philosophy Comparison

Aspect TypeScript / Node.js Python 3.10+ Key Takeaway for TS Devs
Execution Compiled .ts → .js, runs on V8/Node.js event loop Interpreted bytecode on CPython VM, single-threaded with GIL No compilation step — import and run directly
Types Compile-time enforcement via tsc (stops the build) Static hints checked by mypy/pyright independently of execution Types help but don't enforce at runtime — use Pydantic for validation
Null null and undefined are separate Single None singleton — no distinction needed Just use is not None everywhere
Modules ES Modules (import/export) or CommonJS (require()) PEP 328 import X / from X import Y; directory = package Packages are directories with __init__.py, not files
Concurrency Single-threaded event loop (Node.js) asyncio event loop + threading (I/O-bound) + multiprocessing (CPU-bound) Python has more concurrency primitives than Node.js
Memory GC V8 generational mark-and-sweep Reference counting + cyclic garbage collector Objects die immediately when last ref is dropped in Python
Boolean true / false (lowercase) True / False (capitalized!) Classic trap: true is undefined in Python
Semicolons Optional but common Never used PEP 8 explicitly says no semicolons
Increment i++, i-- exist Only i += 1; no ++ or -- ++i returns + (+i), which is just i — not a counter
Block scope let/const create block scope Only function/module scope — no block scope Loop variables leak after the loop in Python
Optional chaining obj?.prop ?? default dict.get("key", default) / getattr(obj, "prop", default) No ?. or ?? syntax (until Python 3.10+ walrus helps a bit)
Spread { ...obj }, [...arr] {**d}, [*s] — different symbols, same pattern Unpack operator is * / **, not ...
Default args function foo(x = 5) def foo(x=5): — identical concept but with def keyword Be careful: default args are evaluated ONCE at definition time
IIFE (x) => { }() No IIFE needed — use module-level code or if __name__ == "__main__" Python modules ARE the IIFE — top-level scope is isolated per module

Mermaid: High-Level Language Architecture Comparison

graph TD
    subgraph TypeScript_Ecosystem ["TypeScript / Node.js Ecosystem"]
        TS_Code[".ts Source Code"] --> TS_Compile["tsc Compiler"]
        TS_Compile --> JS_Code[".js JavaScript"]
        JS_Code --> V8_Runtime["V8 Engine / Node.js Runtime"]
        V8_Runtime --> EventLoop["Single-Threaded Event Loop"]
        V8_Runtime --> GC["V8 Generational GC"]
        V8_Runtime --> NPM["npm / pnpm / yarn"]
        V8_Runtime --> TSC["tsc (Type Checker)"]
    end

    subgraph Python_Ecosystem ["Python 3.10+ Ecosystem"]
        PY_Code[".py Source Code"] --> PY_VM["CPython Bytecode VM"]
        PY_VM --> GIL["GIL (Global Interpreter Lock)"]
        GIL --> Threading["threading (I/O-bound)"]
        GIL --> Multiprocessing["multiprocessing (CPU-bound)"]
        GIL --> AsyncIO["asyncio (Event Loop)"]
        PY_Code --> MYPI["mypy / pyright (Type Checker)"]
        PY_Code --> RUFF["ruff/black/lint/format"]
        PY_Code --> PIP["pip / Poetry / Hatch"]
    end

    TS_Code -.->|import/export| NPM
    PY_Code -.->|import/from import| PIP

    style TS_Ecosystem fill:#1a8cff,stroke:#0d5fa3,color:white
    style Python_Ecosystem fill:#3776ab,stroke:#265a8c,color:white
Loading

2. Complete Syntax Map — Every Keyword Merged

2a. Language Keywords Table

TypeScript Python Notes
abstract (none) Python uses convention: prefix with _ or docstring
as as Same in both — used in type casting / exception handling
assert assert Same syntax; raises AssertionError
async async Same — marks function/coroutine
await await Same — awaits a coroutine/future
break break Identical behavior
case (none) Python uses match/case instead of switch/case
catch (none) Python uses except / finally
class class Same keyword; Python uses self parameter
const (none) Python has no constant keyword — convention: UPPER_CASE
continue continue Identical behavior
default (none) Python: default params in function definition
delete del delete obj.prop → del obj.prop
do (none) Python uses while instead of do/while
else else Same — but Python has for/else, while/else, try/except/else
enum enum (module: enum.Enum) TS enum → Python class Color(Enum): Red = 1
export (none) Python: no export — module scope IS the namespace
finally finally Same — in try/except/finally
for for TS: for (let i=0; i<n; i++); Python: for i in range(n): or for item in iterable:
function def function foo() {} → def foo():
if if Same — but Python uses indentation, not braces
implements (none) Python: Protocol for structural subtyping
import import Same keyword; different syntax details (see §9)
in in Same — membership test and loop iteration
interface Protocol / TypedDict No interface in Python — use Protocol for structural typing
is is Same — identity comparison (object reference)
keyof (none) Python: typing.get_type_hints() or getattr introspection
let (none) No variable declaration keyword in Python — just assignment
module (none) Modules are created by importing files/directories
namespace (none) Python: package directories act as namespaces
new __new__ No new keyword; call constructors directly: Point(0, 0)
never Never (from typing) TS never → Python typing.NoReturn / Never
null None Single nullish value in Python
number int / float (via type hints) No separate numeric types at runtime
object object Base of everything; also typing.Any for "any type"
of (none) Used in for ... in; no keyword
private _name / __name Convention: single _ = protected, double __ = name mangling
protected _name Single underscore convention; enforced by linter not compiler
public (none) Everything is public by default in Python
readonly property with only getter / dataclass(frozen=True) No readonly keyword
require import / from ... import No require() in Python
return return Identical
some (none) No equivalent keyword; use union types
static @staticmethod / @classmethod Decorators instead of keyword
string str (via type hints) TS string → Python str
super super() Same concept, same function call syntax
switch match TS: switch/case; Python 3.10+: match/case
throw raise throw Error → raise ValueError
true True Capitalized!
try try Same — followed by except (not catch) in Python
type type / def / class TS type X = ... → Python X = TypeVar('X') or just use directly
typeof type() / isinstance() typeof(x) → type(x).__name__; type guards via isinstance()
undefined None No distinction — only None exists
var (none) No variable declaration keyword — assignment is enough
void None / NoReturn TS void return → Python def foo() -> None:
while while Same — but no do/while in Python
with with Python: context manager; not a direct TS equivalent
yield yield Same — creates generators in both

2b. TypeScript Operators → Python Equivalents

Operator TypeScript Python Notes
Equality ==, === ==, is === → is (identity); == works for value comparison
Inequality !=, !== !=, is not !== → is not
Logical AND && and Python uses word operators
Logical OR \\ or Python uses word operators
Logical NOT ! not Word operator in Python
Ternary x ? a : b a if x else b Reversed order! Condition goes in the middle
Nullish coalesce ?? ?? (Python 3.8+) or .get() for dicts Python 3.8+ supports ??; before that: x if x is not None else default
Optional chaining obj?.prop getattr(obj, 'prop', default) No native ?. in Python
Bitwise AND & & Same
Bitwise OR \ or (logical) / \ (bitwise in some contexts) Prefer `
Bitwise NOT ~ ~ Same
Bitwise XOR ^ ^ Same
Left shift << << Same
Right shift >> >> Same
Exponentiation ** ** Same! (Unlike JS's Math.pow())
Augmented assign +=, -=, etc. +=, -=, etc. Same
Member access .prop, [key] .attr, [key] Same
Array index arr[i] lst[i] Same
Spread/expand ...arr *arr / **dict Different symbol; * for iterables, ** for mappings
Destructuring assign [a, b] = arr a, b = lst Same concept! No brackets needed in Python
Comma operator (a, b) Same as expression: a, b → returns tuple (a, b) In Python, comma creates a tuple; no "comma operator" that discards

3. Type System: Complete Visual Mapping

3a. Primitive Types Comparison Table

TypeScript Python (type hint) Runtime Type Notes
number int / float int, float Python has arbitrary precision integers; no overflow
string str str f-strings: f"Hello {name}"
boolean bool bool Capitalized: True / False
null None type(None) Single singleton; use is None, not == None
undefined (none) — Merged with None in Python
bigint int int Python ints have arbitrary precision natively
symbol enum.Enum / object() Enum, object No native symbol type; use unique objects or Enum

3b. Complex Types Mapping Table

TypeScript Python Equivalent Example (TS) Example (PY)
string[] list[str] ["a", "b"] ["a", "b"] (identical syntax!)
Array<string> list[str] new Array<string>() list[str] via type hint only
[string, number] tuple[str, int] A tuple with fixed types ("a", 42) — immutable!
{ name: string } TypedDict or dataclass { name: "Alice" } dataclass with fields or dict[str, Any]
Record<string, T> dict[str, T] Record<string, number> dict[str, int] — same!
Map<K, V> dict[K, V] / collections.OrderedDict new Map() Plain dict is ordered in Python 3.7+
Set<T> set[T] new Set<number>() {1, 2, 3} — same set literal syntax!
readonly T[] tuple[T, ...] or frozenset Readonly array Use tuple for immutability
Union<A, B> A \ B (TS) → A \ B (PY 3.10+) string \ number str \ int — same pipe syntax!
optional T / T \ null T \ None string \ null str \ None or Optional[str]
interface Protocol / dataclass interface User { name: string } @dataclass; name: str
type alias Type alias (direct) type ID = string ID = str or just use str directly
enum enum.Enum enum Color { Red } class Color(Enum): Red = 1
generic <T> TypeVar("T") + Generic[T] Array<T> from typing import TypeVar; T = TypeVar('T')
keyof T typing.get_type_hints() Runtime reflection Use inspect.signature() or __annotations__
Partial<T> Not built-in; use dataclasses / dict Partial<User> Pass only required fields in a dict
Pick<T, K> TypedDict with specific keys Pick<User, "name"> Define a new TypedDict or use dict[str, str]
Omit<T, K> New TypedDict without keys Omit<User, "id"> Define a subset TypedDict
Required<T> dataclass (all required by default) Required<User> dataclass fields are always required unless field(default=...)
Readonly<T> dataclass(frozen=True) or @property Readonly<User> Use frozen dataclass or read-only property
never Never / NoReturn function(): never def foo() -> Never: ...

3c. Type System Architecture Mermaid Diagram

graph TD
    subgraph TypeScript_Types ["TypeScript Type System"]
        TS_Primitive["Primitives:\nnumber, string, boolean,\nnull, undefined, bigint, symbol"] --> TS_Complex["Complex Types"]
        TS_Complex --> TS_Interface["interface / type alias"]
        TS_Complex --> TS_Gen["Generics: <T>"]
        TS_Compile_Time["Compile-Time Enforcement via tsc"] --- TS_BuiltIn["Built-in Types:\nany, unknown, never,\nvoid, object, Record,\nPartial, Pick, Omit"]
        TS_Interface --> TS_Utility["Utility Types\nPartial, Required, Pick,\nOmit, Readonly, Record"]
    end

    subgraph Python_Types ["Python Type System"]
        PY_Primitive["Primitives (hints):\nint, float, str, bool,\nNoneType"] --> PY_Complex["Complex Hints"]
        PY_Complex --> PY_Dataclass["@dataclass / dataclasses.field"]
        PY_Complex --> PY_Protocol["Protocol\n(structural subtyping)"]
        PY_Complex --> PY_Generic["Generics: TypeVar + Generic"]
        PY_Runtime["Runtime: No Enforcement!\nmypy/pyright check independently"] --- PY_BuiltIn["Built-in Hints:\nAny, Union/X|Y,\nOptional[T], Literal,\nTypedDict, NamedTuple,\nSelf, ParamSpec, Concatenate"]
        PY_Dataclass --> PY_Extensions["Extensions:\nfrozen=True, slots=True,\nfield(default=...),\nfield(init=False)"]
    end

    TS_Interface -.->|equivalent to| PY_Protocol
    TS_Gen -.->|equivalent to| PY_Generic
    TS_Compile_Time -->|"Enforced at compile\n(STOPS the build)"| JS
    PY_Runtime -->|"Independent check\ndoes NOT stop execution"| MYPI

    style TypeScript_Types fill:#1a8cff,stroke:#0d5fa3,color:white
    style Python_Types fill:#3776ab,stroke:#265a8c,color:white
    style TS_Compile_Time fill:#ff4444,stroke:#cc0000,color:white
    style PY_Runtime fill:#ffaa00,stroke:#cc8800
Loading

4. Data Structures: Side-by-Side Complete Reference

4a. Collections Comparison Table

Operation TypeScript Array Python list Notes
Create const arr = [1, 2, 3] [1, 2, 3] Identical syntax!
Append arr.push(4) lst.append(4) .append() only (no push in Python lists)
Insert at index arr.splice(1, 0, 99) lst.insert(1, 99) Same concept
Remove last arr.pop() lst.pop() Identical!
Remove first arr.shift() lst.pop(0) or collections.deque.popleft() No direct equivalent
Find index arr.indexOf(x) lst.index(x) Same method name!
Check exists arr.includes(x) x in lst Python uses in operator
Length arr.length len(lst) Function call, not property
Slice arr.slice(1, 3) lst[1:3] Slice syntax instead of method
Concatenate [...a, ...b] or a.concat(b) a + b or [*a, *b] Both work
Map arr.map(x => x * 2) [x * 2 for x in lst] (list comp) List comprehension is the Pythonic way
Filter arr.filter(x => x > 0) [x for x in lst if x > 0] Filter inside comprehension
Reduce arr.reduce((a, b) => a + b, 0) functools.reduce(operator.add, lst, 0) import from functools
Find element arr.find(x => x > 0) next((x for x in lst if x > 0), None) Generator expression with next()
Every/Some arr.every(x => x > 0) / .some(x => ...) all(lst) / any(lst) Built-in functions!
Join arr.join("-") "-".join(lst) Reversed: separator first
Sort (in-place) arr.sort() lst.sort(reverse=True) Same method name
Reverse arr.reverse() lst.reverse() Identical!
Flat [].flat(Infinity) See itertools recipes or nested loops No built-in flat — use list comp: [y for x in lst for y in x]
Operation TypeScript Map/Set Python equivalent Notes
Create new Map() / new Set() dict() / set() Built-in types, not classes to instantiate
Set/Get map.set(k, v) / .get(k) d[k] = v / d.get(k) Subscript syntax instead of methods
Has key map.has(k) k in d Use in operator
Delete map.delete(k) del d[k] del statement
Size map.size / set.size len(d) / len(s) Function call, not property
Iterate keys for (const k of map.keys()) for k in d: Iterate keys by default
Iterate values for (const v of map.values()) for v in d.values(): Same method name!

4b. Every Collection Type — Code Gallery

// TypeScript: All collection patterns

// Array (mutable list)
const arr: number[] = [1, 2, 3];
arr.push(4);                    // [1, 2, 3, 4]
const first = arr[0];           // 1
const slice = arr.slice(1, 3);  // [2, 3]

// Tuple (fixed-size, fixed-type)
const tuple: [string, number] = ["hello", 42];
const [name, age] = tuple;      // destructuring

// Dictionary (record/object)
const dict: Record<string, number> = { a: 1, b: 2 };
dict.c = 3;                     // add key
const val = dict.a ?? 0;        // optional access

// Set
const set = new Set<number>([1, 2, 3]);
set.add(4);                      // Set {1, 2, 3, 4}
set.has(2);                      // true

// Map
const map = new Map<string, number>();
map.set("a", 1);
map.get("a");                    // 1
# Python: All collection patterns (side-by-side)

# List (mutable array) — same literal syntax!
lst = [1, 2, 3]
lst.append(4)                   # [1, 2, 3, 4]
first = lst[0]                  # 1
slice_ = lst[1:3]               # [2, 3]

# Tuple (fixed-size, fixed-type, immutable)
tup: tuple[str, int] = ("hello", 42)
name, age = tup                 # destructuring — same!

# Dictionary (mutable mapping)
dct: dict[str, int] = {"a": 1, "b": 2}
dct["c"] = 3                    # add key
val = dct.get("a", 0)           # optional access with default

# Set
s: set[int] = {1, 2, 3}
s.add(4)                        # {1, 2, 3, 4}
2 in s                          # True — use 'in' operator!

# OrderedDict (ordered by insertion, default in Python 3.7+)
od: dict[str, int] = {}
od["first"] = 1
od["second"] = 2                # maintains insertion order

4c. Data Structure Decision Tree

flowchart TD
    START(["Need to store\nmultiple values?"]) -->|"Homogeneous (same type)"| HOMO["All items same type?"]
    START -->|"Heterogeneous (different types)"| HET["Items different types?"]

    HOMO -->|"Must modify size"| LIST["Use list []\nMutable, ordered, O(1) append"]
    HOMO -->|"Fixed size, known at runtime"| TUPLE["Use tuple ()\nImmutable, fast, hashable"]
    HOMO -->|"Unique values only"| SET["Use set {{}}\nO(1) lookup, no dups"]

    HET -->|"Key-value pairs"| DICT["Use dict {}\nHash map, O(1) access"]
    HET -->|"Ordered key-value"| SORTED_DICT["Use collections.OrderedDict\nPreserves insertion order"]
    HET -->|"Multiple values per key"| DEFAULTDICT["Use collections.defaultdict\nAuto-create missing keys"]
    HET -->|"Need to count"| COUNTER["Use collections.Counter\nAutomatic counting"]

    LIST -->|"Need deque operations"| DEQUE["Use collections.deque\nO(1) append/pop both ends"]

    style HOMO fill:#4CAF50,color:white
    style HET fill:#2196F3,color:white
    style LIST fill:#FF9800,color:white
    style TUPLE fill:#9C27B0,color:white
    style SET fill:#E91E63,color:white
    style DICT fill:#00BCD4,color:white
Loading

5. Functions & Closures: Complete Comparison

5a. Function Types Table

Concept TypeScript Python Notes
Declaration function foo(x: string): void {} def foo(x: str) -> None: pass def keyword, not function
Arrow function const foo = (x: string): void => {} lambda x: ... (single expression only!) Lambdas in Python are limited — prefer def for multi-line
Default params (x = 5) (x=5) Same syntax!
Optional params (x?: string) (x: str \ None = None) or (x: Optional[str] = None) Must provide default value for optional
Rest params (...args: string[]) *args: tuple[str, ...] *args as varargs; **kwargs for dict
No return void / no annotation None (convention) Return type hint -> None is optional but recommended
Overloading Function overloads at top Not supported — use default params or *args/**kwargs Python doesn't support overload syntax; use @overload for type hints only
Closures Same as JS (lexical scoping) Same! Nonlocal keyword for outer-scope assignment nonlocal x to modify enclosing scope variable

5b. All Function Patterns — Code Gallery

// TypeScript: All function patterns

// Basic function declaration
function greet(name: string, age?: number): string {
  return `Hello ${name}${age ? `, age ${age}` : ''}`;
}

// Arrow function with default params
const add = (a: number, b: number = 10): number => a + b;

// Rest parameters
function sum(...numbers: number[]): number {
  return numbers.reduce((a, b) => a + b, 0);
}

// Callback type
type Callback = (result: string) => void;

// Closures with closure variables
function createCounter(): () => number {
  let count = 0;
  return () => ++count;
}

// Higher-order function
function applyTwice(fn: (x: number) => number, x: number): number {
  return fn(fn(x));
}
# Python: All function patterns (side-by-side)

# Basic function declaration
def greet(name: str, age: int | None = None) -> str:
    suffix = f", age {age}" if age else ""
    return f"Hello {name}{suffix}"

# Lambda (single expression only — keep it simple!)
add = lambda a, b=10: a + b

# *args and **kwargs
def sum_(*numbers: int) -> int:
    return sum(numbers)  # built-in!

# Type hint for callable
from typing import Callable
Callback = Callable[[str], None]

# Closures — use 'nonlocal' to modify enclosing scope
def create_counter():
    count = 0
    def counter() -> int:
        nonlocal count  # key: tells Python to use outer variable
        count += 1
        return count
    return counter

# Higher-order function
def apply_twice(fn: Callable[[int], int], x: int) -> int:
    return fn(fn(x))

6. Classes & OOP: Deep Visual Comparison

6a. Class Features Mapping Table

Feature TypeScript Python Notes
Class declaration class Foo { constructor() {} } class Foo: def __init__(self): pass No constructor() — use __init__
Constructor params constructor(public name: string) def __init__(self, name: str): self.name = name Python: assign in body explicitly
Inheritance class Bar extends Foo class Bar(Foo): pass Parentheses, not keyword
Super call super() or super().method() super().__init__() or super().method() Same concept!
Public Default (no modifier) Default (no modifier) Everything is public by default
Private private x: string _x / __x Convention only; __ triggers name mangling
Protected protected x: string _x (single underscore convention) Linter-enforced, not compiler-enforced
Readonly readonly x: number @property with getter only / frozen dataclass No keyword — use property or frozen dataclass
Static member static x = 5; static method() {} x = 5; @staticmethod def method(): pass Decorator for static methods
Abstract class abstract class Base { abstract method(): void } ABC module: @abstractmethod Need from abc import ABC, abstractmethod
Interface interface User { name: string } Protocol / TypedDict Structural typing via Protocols
Type guard instanceof ClassName isinstance(obj, ClassName) Use for runtime type checks
Getter/Setter get x() { return this.x; } set x(v) { this.x = v; } @property def x(self): ... @x.setter def x(self, v): ... Decorator pattern in Python

6b. Complete OOP Patterns Gallery

// TypeScript: Class patterns

class Animal {
  constructor(public name: string, protected sound: string) {}
  
  makeSound(): string {
    return `${this.name} says ${this.sound}`;
  }
  
  static create(name: string): Animal {
    return new Animal(name, "???");
  }
  
  // Abstract base class
}

abstract class Pet extends Animal {
  constructor(name: string) {
    super(name, "???");
  }
  abstract speak(): void;
}

// Interface as contract
interface Feeder {
  feed(animal: Animal): void;
}

// Decorator for behavior modification (simplified)
class Dog extends Pet {
  private _age: number = 0;
  
  get age(): number { return this._age; }
  set age(value: number) { this._age = value; }
  
  speak(): void {
    console.log(`${this.name} barks!`);
  }
}

// Composition over inheritance
class Kennel {
  private animals: Animal[] = [];
  add(animal: Animal) { this.animals.push(animal); }
}
# Python: Class patterns (side-by-side)

class Animal:
    def __init__(self, name: str, sound: str):
        self.name = name           # public
        self._sound = sound         # protected convention
    
    def make_sound(self) -> str:
        return f"{self.name} says {self._sound}"
    
    @staticmethod
    def create(name: str) -> "Animal":
        return Animal(name, "???")

# Abstract base class
from abc import ABC, abstractmethod

class Pet(ABC):
    def __init__(self, name: str):
        super().__init__(name, "???")
    
    @abstractmethod
    def speak(self) -> None: ...

# Protocol (structural typing — equivalent to interface)
from typing import Protocol

class Feeder(Protocol):
    def feed(self, animal: Animal) -> None: ...

# Dataclass for boilerplate reduction
from dataclasses import dataclass

@dataclass(frozen=True)  # immutable like 'readonly'
class Dog(Pet):
    name: str = ""
    _age: int = 0
    
    @property
    def age(self) -> int:
        return self._age
    
    @age.setter
    def age(self, value: int) -> None:
        if value >= 0:
            self._age = value
    
    def speak(self) -> None:
        print(f"{self.name} barks!")

# Composition over inheritance
class Kennel:
    def __init__(self) -> None:
        self.animals: list[Animal] = []
    
    def add(self, animal: Animal) -> None:
        self.animals.append(animal)

6c. OOP Feature Comparison Chart

graph LR
    subgraph TypeScript_OOP ["TypeScript OOP Features"]
        TS_Class["class keyword\nconstructor\nextends\ntype modifiers"] --> TS_Private["@private modifier — compile-time"]
        TS_Class --> TS_Protected["@protected modifier — compile-time"]
        TS_Class --> TS_Public["@public — default"]
        TS_Class --> TS_Readonly["@readonly — compile-time"]
        TS_Class --> TS_Abstract["abstract class\n@abstractmethod"]
        TS_Class --> TS_Interface["interface\ncompile-time contract"]
    end

    subgraph Python_OOP ["Python OOP Features"]
        PY_Class["class keyword\n__init__\nbase classes in parens\nname conventions"] --> PY_Private["_x or __x — convention only"]
        PY_Class --> PY_Protected["_x — convention only"]
        PY_Class --> PY_Public["No prefix — always public"]
        PY_Class --> PY_Frozen["@dataclass(frozen=True)\n@property getter-only"]
        PY_Class --> PY_Abstract["abc.ABC\n@abstractmethod decorator"]
        PY_Class --> PY_Protocol["typing.Protocol\nruntime structural typing"]
    end

    TS_Private -.->|"compile-time\nenforcement"| COMPILER
    TS_Protected -.->|"compile-time\nenforcement"| COMPILER
    TS_Readonly -.->|"compile-time\nenforcement"| COMPILER
    TS_Interface -.->|"compile-time\ncontract"| COMPILER
    
    PY_Private -.->|"runtime\nconvention only"| RUNTIME
    PY_Protected -.->|"runtime\nconvention only"| RUNTIME
    PY_Abstract -.->|"runtime\nabstract enforcement"| RUNTIME
    PY_Protocol -.->|"runtime\nstructural check"| RUNTIME

    style TypeScript_OOP fill:#1a8cff,stroke:#0d5fa3,color:white
    style Python_OOP fill:#3776ab,stroke:#265a8c,color:white
    style COMPILER fill:#ff6b6b,stroke:#cc4444,color:white
    style RUNTIME fill:#ffd93d,stroke:#ccaa00
Loading

7. Async/Await & Concurrency: Architecture Comparison

7a. Concurrency Models Table

Model TypeScript/Node.js Python When to Use
Event loop (async) Native — everything is async-first asyncio module I/O-bound: HTTP requests, file ops, DB queries
Threading Worker threads (limited use) threading module I/O-bound only (GIL prevents CPU parallelism)
Multiprocessing child_process.fork() multiprocessing module CPU-bound: data processing, computations
Web Workers new Worker() concurrent.futures.ProcessPoolExecutor Heavy computation off main thread
Promise new Promise((resolve, reject) => {}) asyncio.Task / asyncio.Future Same concept, different API

7b. All Patterns — Code Gallery

// TypeScript: Async patterns

// Basic async/await
async function fetchData(url: string): Promise<User> {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  return response.json();
}

// Parallel execution
const [user, posts] = await Promise.all([
  fetch("/api/user").then(r => r.json()),
  fetch("/api/posts").then(r => r.json()),
]);

// Timeout with promise
const timeout = (ms: number) => new Promise((_, rej) =>
  setTimeout(() => rej(new Error('Timeout')), ms)
);
const result = await Promise.race([fetchData(url), timeout(5000)]);

// Retry pattern
async function retry<T>(fn: () => Promise<T>, maxRetries: number): Promise<T> {
  for (let i = 0; i < maxRetries; i++) {
    try { return await fn(); }
    catch (e) { if (i === maxRetries - 1) throw e; }
  }
}

// AbortController (cancel request)
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
const res = await fetch(url, { signal: controller.signal });
# Python: Async patterns (side-by-side)

import asyncio
import httpx  # pip install httpx

# Basic async/await
async def fetch_data(url: str) -> User:
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        response.raise_for_status()
        return response.json()

# Parallel execution
user, posts = await asyncio.gather(
    fetch_data("/api/user"),
    fetch_data("/api/posts"),
)

# Timeout with try/except
async def timeout_wrapper(coro, seconds: float):
    try:
        return await asyncio.wait_for(coro, timeout=seconds)
    except asyncio.TimeoutError:
        raise TimeoutError(f"Timed out after {seconds}s")

result = await timeout_wrapper(fetch_data(url), 5.0)

# Retry pattern
async def retry(fn, max_retries: int = 3):
    for i in range(max_retries):
        try:
            return await fn()
        except Exception as e:
            if i == max_retries - 1:
                raise
            await asyncio.sleep(2 ** i)  # exponential backoff

# Cancel with task cancellation
task = asyncio.create_task(fetch_data(url))
asyncio.get_event_loop().call_later(5.0, task.cancel)
await task  # raises asyncio.CancelledError

7c. Concurrency Decision Tree

flowchart TD
    START["What kind of task?"] -->|"I/O-bound\n(waiting on network/files/DB)"| IO["Use async/await + event loop"]
    IO --> PY_ASYNCIO["asyncio gather for parallelism\nhttpx/http for HTTP\naiofiles for files"]
    IO --> TS_ASYNC["Native async/await in TS\naxios/fetch for HTTP"]

    START -->|"CPU-bound\n(computation, data processing)"| CPU["Use multiprocessing!"]
    CPU --> PY_MULTI["multiprocessing.Pool.map()\nProcessPoolExecutor"]
    CPU --> TS_CHILD["child_process.fork()\ncross-spawn for parallel cmds"]

    START -->|"Mix of I/O + CPU"| MIX["Split the workload"]
    MIX --> PY_MIX["asyncio for I/O\n+ ProcessPoolExecutor for CPU"]
    MIX --> TS_MIX["async/await for I/O\n+ Worker threads or child_process"]

    PY_ASYNCIO -.->|"Best for:\nweb scrapers, API clients,\nchat servers"| EXAMPLES
    TS_ASYNC -.->|"Best for:\nAPI servers, real-time apps"| EXAMPLES
    PY_MULTI -.->|"Best for:\ndata processing, image/video\ntranscoding, ML inference"| EXAMPLES
    TS_CHILD -.->|"Best for:\nbilling, compression,\nparsing large files"| EXAMPLES

    style START fill:#FF9800,color:white
    style IO fill:#4CAF50,color:white
    style CPU fill:#F44336,color:white
    style MIX fill:#2196F3,color:white
Loading

8. Error Handling: Complete Mapping

8a. Exception Hierarchy Mermaid Diagram

graph TD
    subgraph Python_Exceptions ["Python Exception Hierarchy"]
        Base["BaseException"] --> SystemExit["SystemExit"]
        Base --> KeyboardInterrupt["KeyboardInterrupt"]
        Base --> GeneratorExit["GeneratorExit"]
        Base --> Exception["Exception"]
        
        Exception --> StopIteration["StopIteration"]
        Exception --> ArithmeticError["ArithmeticError"]
        ArithmeticError --> ZeroDivision["ZeroDivisionError"]
        ArithmeticError --> FloatingPoint["FloatingPointError"]
        
        Exception --> AssertionError["AssertionError"]
        Exception --> AttributeError["AttributeError"]
        Exception --> BufferError["BufferError"]
        Exception --> EOFError["EOFError"]
        Exception --> ImportError["ImportError"]
        ImportError --> ModuleNotFound["ModuleNotFoundError"]
        Exception --> LookupError["LookupError"]
        LookupError --> IndexError["IndexError"]
        LookupError --> KeyError["KeyError"]
        Exception --> MemoryError["MemoryError"]
        Exception --> NameError["NameError"]
        Exception --> OSError["OSError"]
        Exception --> RuntimeError["RuntimeError"]
        Exception --> SyntaxError["SyntaxError"]
        Exception --> TypeError["TypeError"]
        Exception --> ValueError["ValueError"]
    end

    subgraph TypeScript_Errors ["TypeScript Error Classes"]
        TS_Base["Error / DOMException /\nTypeScript Compiled Errors"]
        TS_Base --> TS_TypeError["TypeError"]
        TS_Base --> TS_ReferenceError["ReferenceError"]
        TS_Base --> TS_RangeError["RangeError"]
        TS_Base --> TS_SyntaxError["SyntaxError"]
        TS_Base --> TS_URIError["URIError"]
        TS_Base --> TS_Custom[".custom Error('msg')"]
    end

    Python_Exception -.->|"similar to"| TS_TypeError
    Python_ValueError -.->|"similar to"| TS_RangeError
    Python_KeyError -.->|"Python only: no direct TS equivalent"| EMPTY["No TS equivalent\n(dict key missing)"]
    Python_AttributeError -.->|"similar to"| TS_ReferenceError

    style Python_Exceptions fill:#3776ab,stroke:#265a8c,color:white
    style TypeScript_Errors fill:#1a8cff,stroke:#0d5fa3,color:white
Loading

8b. Patterns Gallery

// TypeScript: Error handling patterns

// Try/catch with typed error
try {
  throw new Error("Something went wrong");
} catch (e) {
  if (e instanceof Error) {
    console.error(e.message);
  }
}

// Custom error class
class ValidationError extends Error {
  public fields: string[];
  constructor(message: string, fields: string[]) {
    super(message);
    this.name = "ValidationError";
    this.fields = fields;
  }
}

// Guarded access (optional chaining)
const name = user?.profile?.address?.street ?? "Unknown";

// Result pattern (using a library or manual enum)
function parseNumber(input: string): { ok: true; value: number } | { ok: false; error: string } {
  const n = Number(input);
  return isNaN(n) ? { ok: false, error: "Invalid" } : { ok: true, value: n };
}
# Python: Error handling patterns (side-by-side)

# Try/except with type-based catching
try:
    raise ValueError("Something went wrong")
except ValueError as e:
    print(f"Error: {e}")  # catch specific types first!
except Exception as e:
    print(f"Unexpected error: {e}")

# Custom exception class
class ValidationError(Exception):
    def __init__(self, message: str, fields: list[str]):
        super().__init__(message)
        self.fields = fields  # store extra info on the exception!

# Guarded access (dict.get / getattr with default)
name = getattr(getattr(user, "profile", None), "address", None) \
    and getattr(user.profile.address, "street", "Unknown") \
    or "Unknown"
# Better: use a helper function or Pydantic for validation

# Result pattern (Python idiom: try/except instead of checking)
def parse_number(input_str: str) -> int | None:
    """EAFP: Try first, handle failure."""
    try:
        return int(input_str)
    except (ValueError, TypeError):
        return None

9. Modules & Packages: Ecosystem Comparison

9a. Module Resolution Table

Feature TypeScript / Node.js Python Notes
Import syntax import { foo } from "bar" from bar import foo Pipe {} → word import
Default import import foo from "bar" import bar; foo = bar.foo or from bar import foo as foo_alias No default exports in Python!
Namespace import import * as foo from "bar" import bar as foo or from bar import * (avoid) import bar as foo is the Pythonic way
Side-effect import import "bar"; bar.init() import bar (runs top-level code) Same — imports execute module body
Relative import ./foo / ../bar from . import foo / from ..pkg import bar Dot-notation required for relative
Dynamic import import("bar").then(m => ...) importlib.import_module("bar") or __import__("bar") Use importlib module
Module resolution node_modules/, baseUrl in tsconfig sys.path, project root, package __init__.py Python uses import paths, not file-relative
Package.json config "module": "esm", "main": "dist/index.js" pyproject.toml or setup.py Poetry/pyproject is the modern standard

9b. Package Managers: npm/pnpm/yarn vs pip/Poetry/Hatch

Feature npm pnpm yarn pip Poetry Hatch
Lock file package-lock.json pnpm-lock.yaml yarn.lock pip freeze / .installed poetry.lock hatchling (no lock by default)
Install deps npm install pkg pnpm add pkg yarn add pkg pip install pkg poetry add pkg pipx install pkg / hatch
Dev deps npm install --save-dev pnpm add -D yarn add -D pip install -e .[dev] poetry add -G dev pkg Hatch extras via pyproject.toml
Scripts "scripts": {"build": "tsc"} Same Same Not built-in; use Makefile/just poetry run mypy . hatch run lint:mypy
Publish npm publish pnpm publish yarn publish twine upload dist/* poetry publish hatch publish
Workspace npm workspaces pnpm workspace yarn workspaces Poetry [tool.poetry.packages] Hatch monorepo Same as Poetry

10. Tooling Ecosystem: Complete Mapping

10a. Tooling Table

Task TypeScript/Node.js Python Equivalent Notes
Type checker tsc (strict mode) mypy / pyright mypy is closest to tsc; pyright = fast (VS Code default)
Linter ESLint ruff (replaces flake8, pylint, etc.) ruff is a single-tool replacement for the entire Python linting ecosystem
Formatter Prettier / prettier-plugin black / ruff format black formats everything automatically — no config needed!
Package manager npm / pnpm / yarn pip + Poetry / pipx Poetry = npm for dependencies; pipx = npx for running tools
Test runner Jest / Vitest / ts-jest pytest (+ pytest-asyncio) pytest discovers tests automatically; fixtures replace setup/teardown
CI/CD GitHub Actions (npm: ci, build, test) GitHub Actions (python: venv, pip install, pytest, mypy, ruff) Same CI tooling — different language steps
Build tool Vite / esbuild / tsup Hatch / poetry-build / maturin (for C extensions) Python doesn't need build tools for pure Python — just pip install .
Hot reload nodemon / ts-node-dev uvicorn --reload / python -Wd uvicorn main:app --reload for FastAPI dev
CLI framework Commander / Argparse / yargs argparse (stdlib) / click / typer Typer = most TS-like (uses type hints for CLI args!)

10b. Tooling Architecture Mermaid Diagram

graph TD
    subgraph TS_Development_Pipeline ["TypeScript Development Pipeline"]
        SRC["Source Code (.ts)"] --> LINT["ESLint\n(Lint + Rules)"]
        SRC --> FORMAT["Prettier\n(Format Code)"]
        SRC --> TYPE_CHECK["tsc --strict\n(Type Checking)\nSTOPS on errors"]
        LINT --> COMPILE["Compile → .js"]
        FORMAT --> COMPILE
        TYPE_CHECK --> TEST["Jest / Vitest\n(Run Tests)"]
        COMPILE --> TEST
        TEST --> DEPLOY["npm publish / deploy"]
    end

    subgraph Python_Development_Pipeline ["Python Development Pipeline"]
        PYSRC["Source Code (.py)"] --> LINT_PY["ruff check\n(Lint + Rules)\nreplaces flake8+pylint"]
        PYSRC --> FORMAT_PY["black / ruff format\n(Format Code)\nno config needed!"]
        PYSRC --> TYPE_CHECK_PY["mypy or pyright\n(Type Checking)\nINDEPENDENT of execution"]
        LINT_PY --> RUNPY["Direct Execution\n(no compile step)"]
        FORMAT_PY --> RUNPY
        TYPE_CHECK_PY --> TEST_PY["pytest + pytest-asyncio\n(Run Tests)"]
        RUNPY --> TEST_PY
        TEST_PY --> DEPLOY_PY["poetry publish / pip install ."]
    end

    LINT -.->|"replaced by"| LINT_PY
    FORMAT -.->|"replaced by"| FORMAT_PY
    TYPE_CHECK -.->|"similar to"| TYPE_CHECK_PY
    TEST -.->|"similar to"| TEST_PY

    style TS_Development_Pipeline fill:#1a8cff,stroke:#0d5fa3,color:white
    style Python_Development_Pipeline fill:#3776ab,stroke:#265a8c,color:white
Loading

11. Testing: Jest → pytest Complete Mapping

11a. Testing Framework Comparison

Feature Jest (TypeScript) pytest (Python) Notes
Test discovery *.test.ts or *.spec.ts files test_*.py / *_test.py files Both auto-discover
Describe/It describe("suite", () => it("test", ...)) def test_name(): pass (no describe needed) pytest uses plain functions
Before/After hooks beforeEach, afterEach @pytest.fixture + yield or setup_method Fixtures are more powerful
Assertions expect(value).toBe(expected) assert value == expected Same assert keyword!
Mocking jest.mock(), jest.fn() unittest.mock.patch(), MagicMock More powerful in Python
Parametrize tests test.each\` ` @pytest.mark.parametrize Both support data-driven tests
Timeout jest.setTimeout(ms) @pytest.mark.timeout(n) pytest-timeout plugin
Coverage --coverage (built-in) pytest-cov plugin Separate plugin in Python

11b. Patterns Gallery

// TypeScript: Jest test patterns

describe("UserService", () => {
  let service: UserService;
  
  beforeEach(() => {
    service = new UserService(mockRepo);
  });
  
  afterEach(() => {
    jest.clearAllMocks();
  });
  
  it("should create a user", async () => {
    const user = await service.createUser({ name: "Alice" });
    expect(user.name).toBe("Alice");
    expect(user.id).toBeDefined();
    expect(mockRepo.save).toHaveBeenCalledTimes(1);
  });
  
  it.each([
    ["", "Name is required"],
    [null, "Name is required"],
  ])("should validate name: %s", (name, expectedError) => {
    expect(() => service.createUser({ name })).toThrow(expectedError);
  });
  
  test("with mock implementation", () => {
    const mockFn = jest.fn().mockReturnValue(42);
    expect(mockFn()).toBe(42);
    expect(mockFn).toHaveBeenCalledWith();
  });
});
# Python: pytest test patterns (side-by-side)

import pytest
from unittest.mock import patch, MagicMock
from app.user_service import UserService


class TestUserService:
    @pytest.fixture
    def mock_repo(self):
        return MagicMock()
    
    @pytest.fixture
    def service(self, mock_repo):
        """Auto-injected via fixture name match!"""
        return UserService(mock_repo)

    def test_create_user(self, service):
        user = service.create_user(name="Alice")
        assert user.name == "Alice"
        assert user.id is not None
        service.repo.save.assert_called_once()

    @pytest.mark.parametrize("name,expected_error", [
        ("", "Name is required"),
        (None, "Name is required"),
    ])
    def test_validate_name(self, name, expected_error, service):
        with pytest.raises(ValueError, match=expected_error):
            service.create_user(name=name)

    @patch("app.user_service.get_external_data")
    def test_with_mock(self, mock_fn, service):
        mock_fn.return_value = 42
        assert mock_fn() == 42
        mock_fn.assert_called_once()

# Async tests — use pytest-asyncio plugin
@pytest.mark.asyncio
async def test_async_user_fetch(service):
    user = await service.get_user(1)
    assert user is not None

12. Web Development: Express/NestJS → FastAPI/Django

12a. Framework Comparison Table

Feature Express.js (TS) NestJS (TS) FastAPI (Python) Django (Python)
Routing app.get("/path", handler) @Get("/path") decorator @app.get("/path") decorator URLconf + function/class views
Type safety Manual (or tRPC) Decorators + DTO classes Type hints = auto-docs! Pydantic models (same as FastAPI)
Middleware app.use(middleware) NestJS interceptors/guards Depends/DependsFastAPI middleware Django middlewares in settings
ORM TypeORM / Prisma TypeORM / Prisma SQLAlchemy 2.0 + alembic Django ORM (built-in!)
Validation Zod class-validator DTOs + class-validator Pydantic v2 (auto from type hints) Pydantic / form validation
Auto docs none (or swagger manually) @nestjs/swagger OpenAPI/Swagger auto-generated! DRF browsable API
Scaffolding express-generator nest generate fastapi new (via uv) django-admin startproject

12b. Complete CRUD Gallery

// TypeScript/Node.js: Express + NestJS patterns

// Express-style REST API
import express from "express";
const app = express();
app.use(express.json());

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

let users: User[] = [];
let nextId = 1;

app.get("/api/users", (req, res) => {
  const page = parseInt(req.query.page as string) || 1;
  const limit = parseInt(req.query.limit as string) || 20;
  const search = (req.query.search as string) ?? "";
  
  let filtered = users.filter(u => 
    u.name.toLowerCase().includes(search.toLowerCase())
  );
  
  res.json({
    data: filtered.slice((page - 1) * limit, page * limit),
    total: filtered.length,
  });
});

app.post("/api/users", async (req, res) => {
  const { name, email } = req.body;
  const errors: string[] = [];
  if (!name) errors.push("Name required");
  if (!email || !/\S+@\S+/.test(email)) errors.push("Valid email required");
  
  if (errors.length > 0) return res.status(400).json({ errors });

  const newUser = { id: nextId++, name, email };
  users.push(newUser);
  res.status(201).json(newUser);
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server on ${PORT}`));
# Python: FastAPI equivalent (side-by-side) — notice how much less boilerplate!

from fastapi import FastAPI, Query, HTTPException
from pydantic import BaseModel, EmailStr
from typing import Optional

app = FastAPI()

class UserCreate(BaseModel):
    name: str
    email: EmailStr

class UserOut(BaseModel):
    id: int
    name: str
    email: EmailStr

users_db: list[UserOut] = []
next_id: int = 1

@app.get("/api/users")
async def get_users(
    page: int = Query(default=1, ge=1),
    limit: int = Query(default=20, ge=1),
    search: Optional[str] = None,
):
    filtered = [u for u in users_db if search is None or search.lower() in u.name.lower()]
    return {
        "data": filtered[(page - 1) * limit : page * limit],
        "total": len(filtered),
    }

@app.post("/api/users", status_code=201)
async def create_user(user: UserCreate):
    """Type hints auto-validate! No manual validation needed."""
    users_db.append(UserOut(id=next_id, **user.model_dump()))
    next_id += 1
    return {"id": next_id - 1, "name": user.name, "email": user.email}

# Run: uvicorn main:app --reload

13. Standard Library: Node.js core → Python stdlib

13a. Every Core Module Mapped

Node.js Module Python Equivalent(s) Notes
fs (file system) pathlib.Path, open(), os, shutil pathlib is the modern way
fs/promises aiofiles, async context managers No native async file API — use aiofiles
path pathlib.Path Python's Path > Node.js path.join()
http requests (sync), httpx/aiohttp (async) Node.js http is built-in; Python requires pip install
https requests, httpx with https:// URLs Same as http — no separate module needed
crypto hashlib, cryptography hashlib for hashing; cryptography for encryption
os os, sys, platform Python has os + sys + platform split
process sys, os, platform, signal process.env → os.environ; process.argv → sys.argv
timers time.sleep(), asyncio.sleep() No setInterval — use asyncio periodically or threads
buffer bytes, bytearray, struct, array bytes is immutable buffer; bytearray is mutable
events asyncio.Queue, blinker (third-party) Python doesn't have EventEmitter built-in
child_process subprocess.run(), subprocess.Popen() subprocess module for external processes
dns socket.getaddrinfo(), dnspython (third-party) Basic DNS via socket; advanced via dnspython
dgram (UDP) socket (AF_INET, SOCK_DGRAM) Same socket API but with different flags
url / URLSearchParams urllib.parse, yarl (third-party) urllib.parse for basic; yarl for advanced
zlib / gzip / bz2 zlib, gzip, bz2, lzma built-in! All compression formats in stdlib!
stream iterators, generators, yield, async iter Python's iterator protocol replaces streams
util inspect, functools, copy inspect for introspection; functools for decorators
assert pytest (for tests), built-in assert assert statement works the same
diagnostics_channel logging, sys.monitoring (3.13+) logging module is the standard

13b. Popular npm → PyPI Mapping

npm Package Purpose Python Equivalent (PyPI/stdlib) Stdlib?
Web Frameworks
express Minimalist web framework fastapi / flask / sanic No
nest Opinionated, modular framework fastapi (with typer/DI) No
next Full-stack React framework django / reflex / solara No
koa Lightweight, middleware-heavy sanic / aiohttp No
hapi Configuration-centric framework django No
HTTP & API Clients
axios Promise-based HTTP client httpx / requests No
node-fetch Fetch API polyfill httpx / urllib3 No
superagent Flexible AJAX library httpx No
ky Tiny fetch-based client httpx No
got Human-friendly HTTP requests httpx / requests No
soap SOAP protocol client zeep No
graphql-request Minimal GraphQL client gql / strawberry No
Database & ORM
prisma Type-safe ORM sqlalchemy / databases / pony No
typeorm ORM for TS/JS sqlalchemy / django-orm / peewee No
mongoose MongoDB ODM motor / pymongo / beanie No
pg / mysql2 DB drivers (Postgres/MySQL) psycopg / asyncpg / pymysql No
sequelize Promise-based ORM sqlalchemy No
knex SQL query builder sqlalchemy (core) No
redis Redis client redis / aioredis No
ioredis Redis client (Promise-based) redis / aioredis No
Validation & Schema
zod Schema validation pydantic / marshmallow / cerberus No
joi Object schema validation marshmallow / pydantic No
class-validator Decorator-based validation pydantic (compatible with dataclasses) No
yup Schema validation pydantic No
io-ts Runtime type checking pydantic / typeguard No
Auth & Security
passport Auth middleware authlib / fastapi-security No
bcrypt Hashing passwords bcrypt / passlib No
jsonwebtoken JWT handling pyjwt / python-jose No
helmet Security headers helmet (Python port) / fastapi-security No
cors CORS middleware fastapi.middleware.cors / flask-cors No
Testing & Quality
jest Testing framework pytest No
vitest Unit test framework pytest No
mocha Test runner pytest No
chai Assertion library pytest (built-in assert) No
supertest HTTP assertions pytest-httpx / requests-mock No
cypress E2E testing playwright / selenium / robot No
eslint Linter ruff / flake8 / pylint No
prettier Formatter black / ruff format No
husky Git hooks pre-commit No
Logging & Monitoring
winston Multi-transport logging loguru / structlog / logging Partial (stdlib logging)
morgan HTTP request logger logging handlers / fastapi-logger Partial
pino Fast JSON logger structlog / python-json-logger No
bugsnag / sentry Error tracking sentry-sdk No
prom-client Prometheus metrics prometheus-client No
Utils & Tooling
lodash Utility functions boltons / toolz / more-itertools Partial (stdlib has itertools, functools)
date-fns Date manipulation pendulum / arrow / dateutil Partial (stdlib datetime)
moment Date parsing/formatting pendulum / arrow No
chalk Terminal colors rich / colorama / blessed No
commander CLI framework typer / click / argparse Partial (stdlib argparse)
inquirer Interactive CLI prompts questionary / inquirer No
ora Terminal spinners halo / rich.progress No
dotenv Env var loading python-dotenv / pydantic-settings Partial (stdlib os.environ)
config Config management dynaconf / pydantic-settings No
nodemon Auto-reload dev server watchfiles / uvicorn --reload No
pm2 Process manager supervisor / gunicorn No
webpack / vite Bundlers Poetry / Hatch / pip-tools No
semver Semantic versioning packaging Yes!
uuid UUID generation uuid Yes!
csv-parse CSV parsing csv (stdlib) / pandas Partial
js-yaml YAML parsing pyyaml / ruamel.yaml No
xml2js XML parsing xmltodict / lxml No
jszip Zip creation/parsing zipfile (stdlib) Yes!
mime-types MIME lookup mimetypes (stdlib) Yes!
node-schedule Cron jobs schedule / apscheduler No
bull Queue system (Redis) celery (Redis/RabbitMQ) / rq No
socket.io WebSockets socketio / websockets / fastapi-websocket No
ws WebSocket client websockets / httpx (WS support) No

14. Memory & Performance: Architecture Comparison

14a. Memory Models Mermaid Diagram

graph TD
    subgraph V8_Memory ["V8 / Node.js Memory Model"]
        V8_Heap["V8 Heap\nGenerational: New → Old"] --> V8_SC["Scavenger GC (New Space)\nFast copy-out, 0.1-1ms pauses"]
        V8_Heap --> V8_MS["Mark-and-Sweep (Old Space)\nFull GC, 5-50ms pauses"]
        V8_Heap --> V8_SW["Mark-Compact\nDefragmentation"]
        
        V8_TypedArray["TypedArrays (Uint8Array etc.)\n→ Native heap memory"]
        V8_Buffer["Buffer → SharedArrayBuffer / mmap"]
    end

    subgraph Python_Memory ["CPython Memory Model"]
        PY_Stack["Python Stack\nCall frames, local vars\nFixed size per frame"] --> PY_ObjectPool["Object Arena Pool\nSmall objects (< 512 bytes)"]
        PY_Heap["Large Objects (> 512 bytes)\n→ Direct malloc/free"]
        
        PY_RefCount["Reference Counting\nImmediate deallocation\n⚠️ Cycles need GC"] --> PY_CyclicGC["Cyclic Garbage Collector\nDetects reference cycles\nPeriodic, not automatic"]
        
        PY_Interned["Interned Objects\nstrings, small ints\nShared memory for common values"]
    end

    V8_TypedArray -.->|"similar to"| PY_ObjectPool
    V8_Buffer -.->|"similar to"| PY_Heap
    PY_RefCount -.->|"No direct equivalent in JS\nJS relies entirely on GC"| V8_SW

    style V8_Memory fill:#1a8cff,stroke:#0d5fa3,color:white
    style Python_Memory fill:#3776ab,stroke:#265a8c,color:white
Loading

14b. Performance Tips Table

Concern TypeScript/Node.js Best Practice Python Best Practice Why It Matters
Integer math Native number (double-precision) int (arbitrary precision) / array.array('i') for C-like performance Python ints are objects — use array or numpy for bulk numeric ops
String concat Template literals / + " ".join(list_of_strings) String concatenation in loops is O(n²); join() is O(n)
List comprehension .map() chains [x*2 for x in lst] — 5-10x faster than for-loop append List comprehensions are C-speed; avoid manual loops when possible
Dict lookups Map.get() dict[key] or dict.get(key, default) Both O(1) average — hash tables!
Function calls Negligible overhead in V8 Expensive! Minimize function call depth for tight loops Python function calls have ~200ns overhead — use built-ins when possible
Global lookups Module-level vars are fast Cache globals to locals: local_func = module.global_func Global variable access is ~30% slower than local in CPython
JSON JSON.stringify() / parse() json.dumps() / json.loads() — or orjson (10x faster) orjson is the fastest JSON library in Python
HTTP server Express: ~30k req/s single core FastAPI+Uvicorn: ~100k req/s (async uvloop) Async frameworks beat sync by orders of magnitude for I/O
CPU bound Worker threads / cluster mode multiprocessing (bypasses GIL!) or numba JIT GIL limits threading to I/O only — use processes for CPU
Memory per object Node.js objects: ~100-200 bytes overhead Python objects: ~48-56 bytes base + attrs Use __slots__ = True on dataclasses to reduce by ~40%
Profiling console.time(), --prof, Chrome DevTools cProfile, pyinstrument, tracemalloc Python has excellent built-in profiling tools

14. One-Page Quick Reference (Cheat Sheet)

This is your ultra-condensed reference. Print it or keep it pinned.

Category TypeScript Python
Print console.log(x) print(x)
Comment // single / /* multi */ # single / """multi""" (docstring)
Null check if (x == null) or ?. if x is None:
Boolean true, false, !x True, False, not x
String "hello" / 'hello' / `template ${x}` "hello" / 'hello' / f"template {x}"
Number const n = 42 n = 42 (no declaration keyword)
Variable const, let Just assignment: x = 5
Constant readonly in class, const at module level Convention: UPPER_CASE = 5
Function function foo(x: number): number { return x * 2; } def foo(x: int) -> int: return x * 2
Arrow function const add = (a, b) => a + b; add = lambda a, b: a + b
Class class Foo { constructor(p) { this.p = p; } } class Foo: def __init__(self, p): self.p = p
Inheritance extends Bar (Bar) — in parentheses
Interface interface Foo { name: string } @runtime_checkable\nclass Foo(Protocol): name: str
Enum enum Color { Red, Blue } class Color(Enum): Red = 1; Blue = 2
Try/Catch try {} catch (e) {} finally {} try: ... except X: ... finally: ...
Throw throw new Error("msg") raise ValueError("msg")
Import import { foo } from "bar" from bar import foo
Export export const x = 5; (nothing — module scope is the export)
Array const arr = [1, 2, 3] [1, 2, 3] (identical!)
Object/Dict const obj = { a: 1 }; obj = {"a": 1}
Set new Set([1, 2]) {1, 2}
Map new Map() {} (plain dict is ordered by default)
Length/Size arr.length, obj.keys().length len(arr), len(obj)
Append arr.push(x) lst.append(x)
Contains arr.includes(x) or x in obj x in lst or key in dct
Map elements arr.map(x => x * 2) [x * 2 for x in lst]
Filter arr.filter(x => x > 0) [x for x in lst if x > 0]
Reduce arr.reduce((a,b) => a+b, 0) functools.reduce(lambda a,b: a+b, lst, 0)
Async/Await async function f() { const x = await fetch(url); } async def f(): async with httpx.AsyncClient() as c: r = await c.get(url)
Promise.all await Promise.all(promises) await asyncio.gather(coroutines)
Timeout setTimeout(fn, 1000) time.sleep(1) or asyncio.sleep(1)
JSON parse JSON.parse(str) json.loads(str)
JSON stringify JSON.stringify(obj) json.dumps(obj)
Date new Date() / date-fns datetime.now() / pendulum
Regex /pattern/gi / RegExp re.compile(r"pattern") / re.findall(...)
Logging console.log(), winston logging.getLogger(__name__).info()
CLI args process.argv.slice(2) sys.argv[1:]
Environment vars process.env.KEY os.environ["KEY"] / os.getenv("KEY")
Platform check process.platform === "win32" sys.platform == "win32" / platform.system()
File read (sync) fs.readFileSync(path, "utf-8") Path(path).read_text(encoding="utf-8")
File write (sync) fs.writeFileSync(path, content) Path(path).write_text(content, encoding="utf-8")
Directory list fs.readdirSync(dir) list(Path(dir).iterdir())

15. Decision Framework: Choosing the Right Python Construct

This section helps you decide which Python tool to use when faced with a TypeScript pattern. Each decision path answers "What should I use in Python?" for common TypeScript constructs.

flowchart TD
    subgraph Choose_Type ["Need to represent a type/contract?"]
        C1["Fixed structure + serialization?"] -->|"Yes"| DC["@dataclass\n+ pydantic BaseModel"]
        C1 -->|"No"| P["Protocol\n(structural typing)"]
        
        C2["Enum values?"] -->|"Yes"| E["enum.Enum subclass"]
        C2 -->|"No"| T["Plain constants (UPPER_CASE vars)"]
    end

    subgraph Choose_Collection ["Need to store data?"]
        L1["Ordered + mutable + duplicates allowed?"] -->|"Yes"| LL["list []\nUse list comprehension for transforms"]
        L2["Unique items only?"] -->|"Yes"| SS["set {{}}"]
        L3["Key-value pairs?"] -->|"Yes"| DD["dict {}\nUse .get(key, default) for safety"]
        L4["Fixed size + immutable?"] -->|"Yes"| TT["tuple ()"]
        L5["Need counting?"] -->|"Yes"| CC["collections.Counter"]
        L6["Need deque operations (fast ends)?"] -->|"Yes"| DEQUE["collections.deque\nO(1) popleft() / appendleft()"]
    end

    subgraph Choose_Error ["Need error handling?"]
        E1["Expected failure with recovery?"] -->|"Yes"| EX1["try/except with specific types"]
        E2["Programming bug/assertion?"] -->|"Yes"| EX2["assert statement\nor raise AssertionError"]
        E3["Custom context-specific error?"] -->|"Yes"| EX3["class MyError(Exception):\n    def __init__(self, extra_info): ..."]
    end

    subgraph Choose_Concurrency ["Need concurrent execution?"]
        CON1["I/O operations (network, files)?"] -->|"Yes"| ASYNC["asyncio + async/await\nBest for: web servers, scrapers"]
        CON2["CPU operations (calculation, ML)?"] -->|"Yes"| MP["multiprocessing.Pool\nBest for: data processing"]
        CON3["Mix of both?"] -->|"Yes"| MIX["asyncio for I/O +\nProcessPoolExecutor for CPU"]
    end

    style Choose_Type fill:#9C27B0,color:white
    style Choose_Collection fill:#4CAF50,color:white
    style Choose_Error fill:#F44336,color:white
    style Choose_Concurrency fill:#FF9800,color:white
Loading

Quick Decision Cheat Table

You want to... TypeScript approach Python recommendation Why
Define a data contract with validation interface + manual checks @dataclass + pydantic.BaseModel Pydantic validates at runtime; type hints give IDE support
Create a unique identifier enum Status { Active, Inactive } class Status(Enum): ACTIVE = 1 Enum is typed and iterable
Match on multiple patterns switch/case with fallthrough match/case (Python 3.10+) Structured pattern matching; no fallthrough by default
Handle optional deeply nested value obj?.a?.b?.c ?? "default" getattr(getattr(obj, "a", None), "b", {}).get("c", "default") Chain getattr + dict.get — or better: use Pydantic dataclasses
Transform a collection .map(x => x*2).filter(x => x > 0) [x * 2 for x in items if x > 0] Single list comprehension replaces the chain
Find an element by predicate arr.find(x => x.id === 5) next((x for x in items if x.id == 5), None) Generator expression with next() — O(1) short-circuit
Check if all/some match .every(x => valid(x)) / .some(x => ...) all(pred(x) for x in items) / any(pred(x) for x in items) Built-in functions accept generators
Debounce a function lodash.debounce(fn, 300) Custom decorator with time.time() Write a debounce decorator; Python decorators are powerful!
Memoize/cache results memoize (lodash) or manual cache @functools.lru_cache(maxsize=128) Built-in in stdlib — no dependency needed
Create a singleton Module-level pattern or class with private constructor class Singleton: _instance = None; def __new__(cls): ... Or just use a module — Python modules ARE singletons!
Handle environment config dotenv + Zod schema os.environ + pydantic-settings pydantic-settings validates env vars automatically
Run a CLI tool Command-line flags with yargs typer (uses type hints!) or argparse (stdlib) Typer gives you CLI + auto-docs from type hints

16. Common Pitfalls for TypeScript Developers (Quick Reference)

TS Pattern (What you'll instinctively write) ❌ Wrong in Python ✅ Pythonic Way Why It's Wrong
`if (x === null x === undefined)` if x == None: or if x is None or x is Undefined:
const x = obj?.prop ?? default x = getattr(obj, "prop") if hasattr(obj, "prop") else default x = getattr(obj, "prop", default) .get() on dicts; getattr() on objects — both accept default directly
try { return JSON.parse(str); } catch(e) { return null; } try: return json.loads(s) except Exception as e: return None return json.loads(s) if isinstance(s, str) else None or use a helper EAFP (Easier to Ask Forgiveness than Permission) is Pythonic — but be specific about which exceptions you catch
for (let i = 0; i < arr.length; i++) { ... } Manual index counter loop for item in lst: ... or for i, item in enumerate(lst): ... Python's for-in iterates values directly; use enumerate() when you need the index
function foo(a = 1, b = 2) {} Same — def foo(a=1, b=2): pass ✅ Same! But watch mutable defaults: def foo(items=[]) → def foo(items=None): items = items or [] Default args are evaluated ONCE at function definition time; mutable defaults persist across calls!
class Foo { private x: number } Python class with compile-time enforcement of privacy class Foo: def __init__(self): self._x = 5 (single underscore = protected convention) Python has no private keyword — only conventions enforced by linters, not the interpreter
import defaultExport from "module" import module; name = module.defaultExport or from module import defaultExport as name ✅ from module import name Python modules don't have "default exports" — they export everything in their namespace
console.log("x =", x) print(f"x = {x}") Same — f-strings are the go-to formatting method No template literals; use f"..." with {expression} syntax
[...array] (clone) Use slice: arr.copy() or list(arr) or [*arr] lst[:] (slice copy) or list(lst) or lst.copy() All create shallow copies; for deep copy, use copy.deepcopy()
Array.isArray(obj) isinstance(obj, list) or type(obj) is list Same — both work; isinstance() supports inheritance type(x) is list is stricter (no subclass check)

17. Time Complexity Quick Reference

Operation TypeScript Array Python list
Access by index O(1) O(1)
Search (linear) O(n) O(n)
Search (hash-based) Map.has(key) O(1) key in dict O(1)
Push/Append O(1) amortized O(1) amortized
Pop O(1) O(1)
Insert at front O(n) O(n) — use deque.popleft() for O(1)
Delete by value O(n) O(n)
Length O(1) (property) O(1) (function call!)

18. Python-Superior Patterns (Things Python Does Better Than TS)

Pattern Why Python Wins
List comprehensions [x*2 for x in data if x > 0] — single line, C-speed, readable
Context managers (with) with open("file.txt") as f: — automatic resource cleanup; no finally block needed
Decorators @decorator syntax modifies functions/classes at definition time — middleware, caching, auth all become simple decorators
Property descriptors @property lets you add computed attributes with validation — like TypeScript getters but more flexible
Iterator protocol (__iter__) Custom iteration semantics in ~3 lines; enables for x in obj: syntax on any class
Magic/double-underscore methods __str__, __repr__, __getitem__, __len__, __add__ — make your objects behave like built-ins
Metaclasses Class-level hooks for custom type creation — TypeScript has nothing comparable
Generators (yield) Lazy evaluation; process infinite streams with O(1) memory
Standard library breadth collections, itertools, functools, pathlib, enum — most utilities are built-in, no npm equivalent exists

This completes Module 24. You now have a complete reference covering every major concept from all previous modules. Use this as your quick-reference guide when writing Python code.

Quick navigation: