Overview
6 min read
In TypeScript you reach for <T> generics when you want one function or class to work over many types, and interface when you want to describe a shared shape. Rust offers the same two ideas — generics and traits — but builds them on a different foundation: generics are monomorphized into specialized machine code at compile time (not erased like TypeScript’s), traits are nominal contracts you opt into with explicit impl blocks (not structural), and the whole system is governed by trait bounds, trait objects for opt-in dynamic dispatch, and coherence rules that prevent two crates from clashing. This section maps each TypeScript habit onto its idiomatic Rust counterpart, so you can write polymorphic, zero-cost-abstraction code the Rust way.
What You’ll Learn
Section titled “What You’ll Learn”- How TypeScript
<T>generic functions become Rustfn f<T>(...), and why monomorphization (one specialized copy per concrete type) differs from TypeScript’s type erasure — plus the turbofish::<>for when inference needs a hint - How to put type parameters on structs and enums, including multiple type parameters and constraints attached to
implblocks, withOption<T>andResult<T, E>as the canonical generic enums - How a TypeScript
interfacebecomes a trait, written as a separateimpl Trait for Typeblock, and the difference between required and provided (default) methods - How to constrain generics with trait bounds (
<T: Trait>, multiple bounds with+, andwhereclauses), including bounds on return types - When to use trait objects (
&dyn Trait,Box<dyn Trait>) for runtime dynamic dispatch, what dyn compatibility (object safety) requires, and the static-vs-dynamic dispatch trade-off - How
impl Traitworks in argument and return position (RPIT), with a note on return-positionimpl Traitin traits (RPITIT) - How default method implementations and supertraits (one trait requiring another) reduce boilerplate and express prerequisites
- How to overload operators (
Add,Sub,Mul,Index, …) by implementing the corresponding traits, and what the marker traitsSend,Sync,Copy, andSizedsignal to the compiler - Why the orphan rule forbids implementing a foreign trait for a foreign type, and the newtype pattern that works around it
Topics
Section titled “Topics”| Topic | Description |
|---|---|
| Generic Functions | Generic functions <T>; monomorphization vs TypeScript type erasure; the turbofish ::<>. |
| Generic Structs | Generic data structures; multiple type parameters; constraints attached to impl blocks. |
| Generic Enums | Generic enums, with Option<T> and Result<T, E> as the canonical examples. |
| Traits | Interfaces → traits: defining and implementing a trait via the impl Trait for Type syntax. |
| Trait Methods | Required vs provided (default) methods; calling them and overriding defaults. |
| Trait Bounds | Trait bounds <T: Trait>, multiple bounds, where clauses, and bounds on return types. |
| Trait Objects | Dynamic dispatch: &dyn Trait / Box<dyn Trait>, dyn compatibility, and static-vs-dynamic trade-offs. |
impl Trait | impl Trait in argument and return position (RPIT), with a brief note on RPITIT. |
| Default Implementations | Default method bodies and how they cut implementation boilerplate. |
| Supertraits | Supertraits (trait inheritance): requiring one trait as a prerequisite for another. |
| Operator Overloading | Operator traits Add, Sub, Mul, Index, and friends; implementing + for your own type. |
| Marker Traits | Marker traits Send, Sync, Copy, Sized: what they signal, and auto traits. |
| The Orphan Rule | Coherence and the orphan rule; why you cannot impl a foreign trait for a foreign type; the newtype workaround. |
Learning Objectives
Section titled “Learning Objectives”By the end of this section, you will be able to:
- Write generic functions, structs, and enums, and explain how monomorphization turns one generic source into specialized, zero-cost concrete code
- Reach for the turbofish
::<>or a binding annotation exactly when inference needs help, and not before - Define traits, implement them with
impl Trait for Type, and distinguish required methods from provided (default) ones - Constrain a generic with the loosest trait bounds that compile, using
+andwhereclauses for readability - Choose deliberately between static dispatch (generics /
impl Trait) and dynamic dispatch (dyn Trait), and recognize when a trait is not dyn compatible - Use
impl Traitin argument and return position, and know when a trait method that returns animpl Trait(RPITIT) is appropriate - Eliminate boilerplate with default method implementations and express prerequisites with supertraits
- Overload operators by implementing the relevant
std::opstraits, and read whatSend,Sync,Copy, andSizedtell the compiler - Diagnose an orphan-rule error (
E0117) and resolve it by owning the trait or applying the newtype pattern
Prerequisites
Section titled “Prerequisites”- Section 06: Data Structures — structs, enums,
Option<T>, pattern matching, andimplblocks; this section generalizes all of them with type parameters and trait contracts (and completes the light introduction to associated types started there) - Section 05: Ownership — what
&self,&mut self, andselfreceivers mean, plus moves, borrows, andClone, all of which trait method signatures depend on - Section 02: Basics — concrete types (
i32,f64,String), immutability by default, and#[derive(...)]-style trait derivation
Estimated Time
Section titled “Estimated Time”- Reading: 5-6 hours
- Hands-on Practice: 4-5 hours
- Exercises: 3 hours
- Total: 12-14 hours
Tip: Read the topics roughly in listed order. Generics (functions, structs, enums) teach you to abstract over types; traits, their methods, and bounds teach you to abstract over behavior; trait objects and
impl Traitare the two dispatch strategies that tie them together; and operator overloading, marker traits, and the orphan rule are the practical edges you will hit in real code. The biggest mental shift for a TypeScript developer is that Rust generics are monomorphized (real specialized code, not erased) and traits are nominal (you must write an explicitimpl, not just match a shape).
Next: Section 10: Smart Pointers → — Box, Rc/Arc, RefCell/Mutex, Cow, and Weak, where Box<dyn Trait> from this section ties generics and trait objects to heap allocation.