Learning Rust as a TypeScript Developer: Week 1
Why I started learning Rust after years with TypeScript, what the ownership model actually means, and what to expect from this 12-part series.

TypeScript gives you a type system. Rust gives you something different: a type system that also manages memory.
That distinction sounds small until you try to write your first non-trivial Rust program and the compiler refuses to let you make a class of mistakes that JavaScript and TypeScript don’t even know about. Not runtime errors. Not type mismatches. A different category: memory errors that most garbage-collected languages make invisible by handling them for you at runtime.
I’ve been building dashboards, APIs, and mobile backends with TypeScript for years — if you’re still making that jump from JavaScript, my earlier post on TypeScript for JavaScript Developers covers that ground. What I found when I started with Rust is that the type system felt familiar for exactly long enough to make the first real difference surprising. Rust uses the type system to track who owns each piece of data, and that’s where week one gets interesting.
By the end of this post, you’ll have a clear picture of why this language has kept developers’ attention for years, what the ownership model looks like before you go deep, and what the next 11 parts of this series will actually cover.
Series: This is Part 1 of a 12-part series on Rust for TypeScript developers.
On this page
- Why Rust keeps appearing in developer surveys
- The thing TypeScript doesn’t prepare you for
- A first look at ownership
- Where TypeScript developers get stuck first
- The strongest argument against learning Rust
- What this 12-part series covers
- Rust changes what you ask the compiler for
Why Rust keeps appearing in developer surveys
According to the Stack Overflow Developer Survey 2024, Rust has been the most admired programming language for nine consecutive years, with 83% of its users saying they want to continue using it. That isn’t the survey saying it’s the most popular — TypeScript is used by 38.5% of respondents, compared to Rust’s 12.6%. What the admiration score reflects is that developers who have used Rust choose to keep using it at a rate almost no other language matches.
The 2023 Rust Annual Survey offers a more useful number for understanding why. Of the organizations actively using Rust at work, 86% cited “the ability to build relatively correct and bug-free software” as the primary reason — ranking it above performance characteristics, which came in at 83%. That ordering surprised me. Rust is usually described as a systems programming language you choose for speed. The practitioners are choosing it primarily because it’s harder to write incorrect code in it.
That’s the version of Rust that interests me: not the fast language, but the language that makes an entire class of bugs structurally impossible.
The thing TypeScript doesn’t prepare you for
In JavaScript and TypeScript, memory is invisible. The runtime’s garbage collector watches for values that nothing else references, then frees the memory when it decides to. If you’ve gone into how JavaScript execution contexts work — the call stack, the heap, how closures capture variables — you know the engine is doing this work constantly in the background. You almost never think about it, and that’s exactly the point of the abstraction.
Rust has no garbage collector. Memory is freed deterministically, based on rules written into the code itself. The compiler tracks who owns each value, and when the owner goes out of scope, the memory is freed automatically — no runtime, no pause, no dangling pointer. The compiler enforces all of this at build time.
For TypeScript developers, the closest analogy is the jump from JavaScript to TypeScript with strict mode enabled. Before strict mode, you could pass null where the function expected a string and the type checker wouldn’t stop you. With strict, that becomes a compile-time rejection. Rust’s ownership system applies that same idea to memory: errors that would be runtime problems in other languages become compile-time rejections in Rust.
The shift isn’t syntactic. Rust’s structs and enums will feel recognisable. The unfamiliar part is being asked to reason about who is responsible for freeing each piece of memory — and writing code the compiler can verify that reasoning in.
A first look at ownership
Every value in Rust has exactly one owner. When the owner goes out of scope, the value is dropped and the memory is freed. Two owners for the same heap-allocated value isn’t allowed — that would mean two pieces of code both think they’re responsible for freeing it, which is a double-free bug.
Here’s what that looks like compared to TypeScript:
// TypeScript: both variables hold a reference to the same string data
const name = "Soumitra";
const alias = name; // both are valid
console.log(name); // valid
console.log(alias); // valid
fn main() {
let name = String::from("Soumitra"); // heap-allocated String
let alias = name; // ownership moves from name to alias
// println!("{}", name); // compile error: value used after move
println!("{}", alias); // works fine
}
In TypeScript, both name and alias are valid references to the same string. The garbage collector handles cleanup when both go out of scope. In Rust, assigning name to alias moves ownership. After the move, name is no longer valid — using it is a compile error, not a runtime panic.
This is not an arbitrary restriction. It’s a guarantee: if your code compiles, Rust has already verified that you can’t double-free memory, access freed memory, or create a data race by reading and writing the same value from multiple places simultaneously.
One important distinction for week one: Rust copies simple types like integers (i32, bool, f64) instead of moving them — they’re cheap to duplicate and live on the stack. The move behaviour applies to heap-allocated types like String and Vec. Understanding when Rust copies versus moves is the first week’s real task.
Check this before moving on
- JavaScript and TypeScript rely on a garbage collector to free heap memory automatically
- Rust has no garbage collector — the compiler enforces memory rules via ownership at compile time
- After
let alias = name;in Rust,nameis invalid ifnameis a heap-allocatedString
Where TypeScript developers get stuck first
The 2023 Rust Annual Survey asked respondents which areas of Rust they struggled with most. The borrow checker came up consistently, alongside async Rust and the traits system. The borrow checker is the compiler mechanism that enforces the ownership rules — it’s what produces those early errors that seem hard to interpret.
For TypeScript developers, the instinct is to treat Rust references (&value) like JavaScript object references, where the same object can be referenced from many places. They aren’t the same. When you borrow a value in Rust, you’re telling the compiler: “I want to use this without taking ownership.” The compiler tracks how many borrows are active and whether any of them attempt to modify the value. Simultaneous mutation and reading creates data races — and Rust prevents that at compile time, not by luck at runtime.
The first few days writing Rust tend to look like this: you write what seems like simple code, the compiler produces an error you don’t fully understand, you fix it in the way that seems obvious, and the compiler rejects that too. This isn’t the language being difficult for no reason. It’s the compiler pointing at a real problem in your reasoning about ownership — which means the bug you would have shipped in another language is now a conversation with the compiler instead.
That friction shrinks as ownership becomes second nature. But week one is where it’s most visible.
The strongest argument against learning Rust
The honest counterargument: Rust has a steep initial learning curve, and for most web application work, you’ll never need what it provides. If you’re building a Next.js app, a REST API, or a data dashboard, TypeScript handles the safety guarantees you actually need, and the runtime is fast enough. The time cost of learning Rust is real — and it won’t make your TypeScript code directly better.
That argument is correct in its domain. Rust isn’t the right tool for shipping a web feature next week.
Where it breaks down: Rust has moved well beyond systems programming. It’s used for CLIs, WebAssembly modules, build tools, database engines, and backend services where TypeScript is technically capable but less predictable at scale. If you want to understand how a type system that tracks generics and type transformations compares to one that also tracks memory lifetimes, or if you want a clearer picture of why certain performance profiles exist at the language level, Rust is one of the most instructive places to look. You return to TypeScript with a different appreciation for what the runtime is quietly doing for you.
What this 12-part series covers
This series runs through the following ground:
- Parts 1–3: Mental models and fundamentals — ownership, borrowing, lifetimes, and the type system basics that a TypeScript background both helps with and complicates
- Parts 4–6: Practical Rust structures — structs, enums, pattern matching, and traits (Rust’s answer to interfaces and polymorphism)
- Parts 7–9: Error handling, iterators, closures, and the async model — all areas where Rust diverges meaningfully from TypeScript
- Parts 10–12: A real project — building something genuinely useful in Rust, pulling together what the earlier parts covered
Each part stands on its own. If you already understand ownership, skip to part 4. If you’ve been writing Rust for a month and want a clearer picture of async, jump to part 8. The series is designed for someone starting from TypeScript, but it doesn’t require reading in order.
Rust changes what you ask the compiler for
TypeScript made the JavaScript ecosystem safer. It added types on top of a language already running in production, with the runtime handling memory on your behalf. Rust starts from the opposite direction: it makes memory management explicit, then wraps it in a type system expressive enough that most of the cost becomes invisible once you understand the rules.
The thing I noticed after the first week: I started reading Rust error messages differently from TypeScript errors. TypeScript errors are usually about “you passed the wrong type.” Rust errors are usually about “two things are claiming responsibility for this memory at the same time, and exactly one of them can.” That shift in what the compiler is asking you to reason about is the actual lesson of week one — and it changes how you think about what a type system is for.
If you want to follow along: install Rust through rustup.rs, open The Rust Programming Language (the official book, free online), and try writing a function that takes a String, modifies it, and returns it. Then try using the original variable after passing it to the function. See what the compiler says. That error is week one.