type Aliases for Complex Types
The type keyword defines a type alias (type Alias<'a, T> = ExistingType<'a, T>;) that abbreviates deeply nested generic types, callback signatures, associated type projections, and module-specific Result types without introducing a wrapper struct.
Four High-Value Uses of type Aliases
1. Module-Specific Result<T> Shorthands (With Default Error Parameter)
Following the pattern of std::io::Result<T>, defining pub type Result<T, E = MyError> = std::result::Result<T, E>; allows functions in your module to write Result<User> for the default error type while still allowing Result<User, CustomErr> when a specific function returns a different error type:
#[derive(Debug)]
pub enum DbError {
NotFound,
Timeout,
}
// Default type parameter `E = DbError` allows both `DbResult<T>` and `DbResult<T, OtherErr>`:
pub type DbResult<T, E = DbError> = std::result::Result<T, E>;
fn fetch_user(id: u32) -> DbResult<String> {
if id == 1 {
Ok(String::from("alice"))
} else {
Err(DbError::NotFound)
}
}
fn fetch_with_custom_err(id: u32) -> DbResult<String, &'static str> {
fetch_user(id).map_err(|_| "custom error override")
}
fn main() {
println!("default error: {:?}", fetch_user(1));
println!("custom error: {:?}", fetch_with_custom_err(99));
}
default error: Ok("alice")
custom error: Err("custom error override")
2. Abbreviating Boxed Trait-Object Callbacks and Async Futures
Complex higher-ranked closure trait objects (Box<dyn Fn(&Request) -> Response + Send + Sync + 'static>) and pinned boxed futures (Pin<Box<dyn Future<Output = T> + Send + 'a>>) become self-documenting when named via a type alias:
use std::future::Future;
use std::pin::Pin;
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
pub type EventCallback = Box<dyn Fn(&str) + Send + Sync + 'static>;
struct EventBus {
listeners: Vec<EventCallback>,
}
impl EventBus {
fn new() -> Self {
Self {
listeners: Vec::new(),
}
}
fn subscribe(&mut self, callback: EventCallback) {
self.listeners.push(callback);
}
fn publish(&self, event: &str) {
for listener in &self.listeners {
listener(event);
}
}
}
fn main() {
let mut bus = EventBus::new();
bus.subscribe(Box::new(|evt| println!("[listener 1] received: {}", evt)));
bus.subscribe(Box::new(|evt| println!("[listener 2] length: {}", evt.len())));
bus.publish("order.completed");
}
[listener 1] received: order.completed
[listener 2] length: 15
3. Type Aliases Over Associated Type Projections
When a generic signature repeatedly projects through an associated type (<G as Graph>::NodeId), a generic type alias type NodeIdOf<G> = <G as Graph>::NodeId; makes function signatures concise.
Note on Unused Type-Alias Bounds (type_alias_bounds Warning)
In Rust, trait bounds written on the left-hand side of a top-level type alias (type List<T: Clone> = Vec<T>;) are not enforced when the alias is instantiated (and trigger the #[warn(type_alias_bounds)] compiler warning), except when needed to resolve an associated type projection (type ItemOf<I: Iterator> = I::Item;).