Skip to content

Advanced Rust

You have learned Rust’s ownership model, borrowing, and basic types. Now it is time to unlock the tools that make Rust both expressive and zero-cost: a type system powerful enough to replace entire runtime frameworks with compile-time guarantees.

This module maps each concept to something you already know from TypeScript so you can build mental models quickly instead of starting from scratch.

LessonRust conceptTypeScript analogy
Generics & Trait Boundsfn foo<T: Display>(), where clausesGeneric functions with constraints <T extends ...>
Trait Objectsdyn Trait, Box<dyn Trait>Interfaces, polymorphism, runtime dispatch
Closures & IteratorsFn/FnMut/FnOnce, .map()/.filter()/.collect()Arrow functions, Array.prototype.map/filter/reduce
Error Handling (Deep)? operator, thiserror, anyhowtry/catch, typed error classes
Macrosmacro_rules!, derive macrosNo direct equivalent — but closer to TypeScript decorators than you think
Smart PointersBox<T>, Rc<T>, RefCell<T>JavaScript’s garbage-collected references

Why this matters for TypeScript developers

Section titled “Why this matters for TypeScript developers”

TypeScript gives you generics, interfaces, and union error types. Rust takes all three ideas further:

  • Generics are monomorphised — the compiler stamps out a specialised copy for each concrete type. Zero virtual dispatch overhead.
  • Trait objects (dyn Trait) give you the runtime polymorphism you are used to from TypeScript interfaces, but you opt in explicitly.
  • Closures capture by reference or by move, and the Fn* trait hierarchy tells the compiler exactly what that closure can do.
  • Error handling with ? and thiserror is as ergonomic as async/await — and the types force you to handle every failure case.
  • Macros are hygienic and operate on the AST — more powerful and safer than TypeScript string-template code-generation.
  • Smart pointers give you fine-grained control over heap allocation and shared ownership without a garbage collector.

Work through the lessons in order. Each one builds on the last.

Rust generics are monomorphised. What does that mean?
Which Rust feature is the closest equivalent to TypeScript interface-based polymorphism at runtime?
What is the main advantage of Rust's `?` operator over TypeScript's try/catch?