As a TypeScript developer, you’ve likely become accustomed to the flexibility and safety that TypeScript offers. The language’s ability to catch errors early, combined with its strong typing system, makes it a powerful tool for building scalable web applications. But what if I told you that there’s another language that can take your understanding of systems programming to the next level, with an even stronger focus on safety and performance? That language is Rust.
I first decided to learn Rust to build Loadjitsu, a load testing tool using the Tauri framework. Coming from a TypeScript background, I was pleasantly surprised by how quickly I could adapt to Rust. Despite the differences in syntax and some underlying concepts, I found that my experience with TypeScript provided a solid foundation for grasping Rust’s core principles.
In this post, I’m going to show you how Rust can be your next big leap. I’ll walk you through how being a TypeScript developer actually gives you a head start with Rust, making the learning curve less steep and the rewards even greater. By the end, you’ll see why Rust isn’t just for systems programmers or those seeking maximum performance—it’s for anyone who wants to take their coding skills to the next level. Ready to dive in? Let’s get started.
Numbers in Rust
As a TypeScript developer, you're already familiar with the concept of numbers as a fundamental data type. Numbers are crucial in any programming language, and Rust, like TypeScript, provides a robust system for working with them. However, Rust introduces some additional nuances that give you more control over how numbers are handled in your programs. In this section, we'll dive deep into how Rust manages numeric data types, comparing them to what you already know from TypeScript.
Numeric Types: TypeScript vs. Rust
TypeScript:
In TypeScript, all numbers—whether integers or floating-point—are represented by the number
type. This simplicity makes it easy to work with numeric data, but it doesn't provide much control over the specific characteristics of the number, such as its precision or whether it's an integer or floating-point value.
let integer: number = 42;
let float: number = 3.14;
Rust:
Rust, on the other hand, offers a more granular approach by requiring you to specify the exact type of number you're working with. This explicitness allows for better performance optimization and ensures that your code behaves exactly as intended.
let integer: i32 = 42;
let float: f64 = 3.14;
In Rust, you have several numeric types to choose from, categorized into:
-
Integers:
i8
,i16
,i32
,i64
,i128
,isize
for signed integers, andu8
,u16
,u32
,u64
,u128
,usize
for unsigned integers. -
Floating-Point Numbers:
f32
andf64
.
Signed and Unsigned Integers
One of the key distinctions Rust introduces is between signed and unsigned integers. This concept may be new if you're primarily familiar with TypeScript, where such distinctions aren't necessary.
-
Signed Integers (
i8
,i16
,i32
, etc.): These can represent both positive and negative numbers. -
Unsigned Integers (
u8
,u16
,u32
, etc.): These can only represent non-negative numbers, allowing them to store larger positive values compared to their signed counterparts of the same bit size.
let signed_integer: i32 = -10;
let unsigned_integer: u32 = 10;
Rust's distinction between signed and unsigned integers ensures that you're explicitly aware of the range and behavior of the numbers you're working with, which can prevent certain types of bugs that might slip through in a language like TypeScript.
Floating-Point Numbers
Both TypeScript and Rust handle floating-point numbers, but Rust, once again, requires explicit type declarations to ensure that the level of precision is clear.
-
TypeScript: All floating-point numbers are of type
number
.
let pi: number = 3.14159;
-
Rust: Floating-point numbers can be either
f32
(single precision) orf64
(double precision).
let pi: f64 = 3.14159;
The concept of floating-point numbers is similar in both languages. However, Rust's explicitness helps avoid unexpected behavior due to precision issues, which can be crucial in scientific calculations or applications where exact precision is critical.
Numeric Operations
Both TypeScript and Rust allow you to perform standard arithmetic operations on numbers, such as addition, subtraction, multiplication, and division.
TypeScript:
let sum = 5 + 10;
let difference = 15 - 5;
let product = 2 * 3;
let quotient = 10 / 2;
Rust:
let sum = 5 + 10;
let difference = 15 - 5;
let product = 2 * 3;
let quotient = 10 / 2;
Arithmetic operations work nearly identically in both TypeScript and Rust. If you're comfortable with basic math in TypeScript, you'll find it easy to transfer those skills to Rust.
Overflow and Underflow
One area where Rust introduces a more rigorous approach is in handling numeric overflow and underflow. Rust’s strict rules help prevent the kind of errors that can occur in TypeScript when a number exceeds the maximum value that can be represented by a given type.
-
TypeScript: JavaScript’s
number
type (which TypeScript is based on) can represent values up toNumber.MAX_SAFE_INTEGER
. However, if a number exceeds this value, it may result in unexpected behavior without any warning. - Rust: Rust will panic in debug mode if an integer overflows, helping you catch potential issues during development. In release mode, Rust performs two’s complement wrapping by default, but you can opt for other behaviors (like saturating arithmetic) if needed.
let max_u8 = u8::MAX;
let overflow = max_u8 + 1; // This will panic in debug mode
Rust’s strict handling of overflow and underflow ensures greater safety and predictability, which is particularly important in systems programming or applications where numerical accuracy is crucial.
That is it for now, in the next blog in this series, we will talk of mutability and immutabilty in rust.
Read the next post in this series "Rust for typescript devs"
Immutabilty
Top comments (0)