PONY λ M2 Modula-2
for TypeScript programmers

You already know TypeScript.Now explore other languages.

Side-by-side, interactive cheatsheets for TypeScript programmers
comparing TypeScript to other languages. Every example runs live in your browser — no setup, no installation.

▶ Start with Go Browse comparisons ↓

Choose your own path by reordering languages

Go Pre-Alpha

Static types you already love, plus true parallelism and one deployable binary. A TypeScript developer moving to Go keeps compile-time type safety and inference, but trades the event loop and structural typing for goroutines, nominal types with zero values, and errors as ordinary return values.

  • Goroutines and channels run on every CPU core — Go offers real parallelism where async/await is concurrency on a single thread
  • Errors are returned values checked with if err != nil — there is no throw/catch for ordinary failures, and the signature shows what can fail
  • Every type has a zero value, so an uninitialized variable is 0 or "" — never undefined; no strictNullChecks needed
  • Interfaces are satisfied implicitly, like structural typing, but checked by the compiler — and there is no any escape hatch
  • Compiles to one static binary with no node_modules and no transpile step — go build is the whole toolchain
JavaScript Alpha ⚡ Works Offline ⚡ Offline

You already know JavaScript — this page is about what is actually real at runtime. What the compiler erases, what it quietly emits as running code, where the types stop protecting you, and how to keep type safety in plain JavaScript with JSDoc and no build step.

  • What disappears: annotations, interface/type, generics, as, satisfies, and ! are all erased — and private is only advisory
  • What emits code: enum builds a runtime object, namespace an IIFE, and parameter properties generate this.x = x
  • Why types cannot be trusted at runtime — JSON.parse/fetch return any, indexing lies, and you cannot instanceof an interface
  • What is real ECMAScript, not TypeScript: #private fields, ?., and ?? survive compilation and run in plain JS
  • Keeping type safety without a build step — JSDoc @typedef/@param checked by tsc, plus runtime validation (zod) at the boundary
Python Beta ⚡ Works Offline ⚡ Offline

The dynamic language a TypeScript developer reaches for in data, scripting, and ML. Python keeps annotations optional and unenforced, trading compile-time guarantees and structural typing for whitespace blocks, comprehensions, and a runtime that just runs — no build step at all.

  • Type hints use the same name: type / | None syntax, but they are advisory — mypy checks them, the interpreter ignores them
  • List, dict, and set comprehensions fold filter/map into one expression, replacing chained array methods
  • Real keyword and default arguments instead of an options object; match does structural patterns like a discriminated union
  • Indentation defines blocks — no braces, no semicolons — and empty collections are falsy, so if not items tests for empty
  • @dataclass gives value equality and a constructor for free, the closest analogue to a TypeScript record-shaped interface
Ruby ⚡ Works Offline ⚡ Offline

What a TypeScript developer reaches for when the type system stops earning its keep. Ruby drops annotations, the compile step, and structural typing for duck typing, blocks, and an object model so uniform that even integers and nil are real objects with methods — the language behind Rails.

  • Blocks instead of arrow-function callbacks — numbers.map { |number| number * 2 }, with the &:upcase shorthand for one-method calls
  • Everything is an object with a class, including 42 and nil — no primitive/wrapper split, no undefined; only nil and false are falsy
  • Real keyword arguments and "endless" one-line methods (def square(x) = x * x) replace options objects and arrow functions
  • Structural pattern matching with case/in — destructure hashes and arrays the way you would with a discriminated union, plus guards
  • Open classes and method_missing give runtime metaprogramming that a Proxy only approximates
Rust Pre-Alpha

The type discipline taken all the way down. A TypeScript developer learning Rust keeps generics, closures, and discriminated unions, but the checks now run at compile time over real memory: ownership replaces the garbage collector, and Option/Result replace null and throw.

  • Option<T> replaces T | undefined and Result<T, E> replaces throw — absence and failure are values the compiler forces you to handle
  • Ownership and borrowing replace the garbage collector — deterministic cleanup and data races caught at compile time, with no runtime
  • Enums are true sum types with exhaustive match — discriminated unions made first-class, and the compiler rejects an unhandled case
  • Traits with bounded generics are like interfaces, but implemented explicitly and monomorphised — no structural any to fall back on
  • Iterator adapters (map/filter/collect) are lazy, zero-cost pipelines that read like the array methods you already use
C# Pre-Alpha

The language TypeScript was modeled on — same lead designer, Anders Hejlsberg. C# gives a TypeScript developer the type system they already love, but reified at runtime and compiled to native-speed IL: nominal interfaces, real generics, value types, and records, with no erasure and no any.

  • Generics are reified — typeof(T) works at runtime, unlike TypeScript's erased type parameters
  • Nullable reference types (string?, ?., ??) are exactly strictNullChecks — the operators TypeScript borrowed from C#
  • record types bring value equality and a with expression; switch expressions add exhaustive, type-narrowing pattern matching
  • LINQ is filter/map/reduce as lazy Where/Select/Aggregate over any sequence
  • Interfaces are nominal and checked — a type must declare : IFoo, where TypeScript accepts any matching shape
Drag cards to reorder · your order is saved locally