Type aliases create readable names for complex types. NewType creates distinct types.
1from typing import TypeAlias, NewType23# TypeAlias — readable name4UserID: TypeAlias = int5JSON: TypeAlias = dict[str, any]6Handler: TypeAlias = callable[[str, int], bool]78def get_user(user_id: UserID) -> JSON:9 return {"id": user_id}1011# NewType — distinct type (checked at compile time)12UserID = NewType("UserID", int)13OrderID = NewType("OrderID", int)1415def get_user(user_id: UserID) -> dict:16 return {"id": user_id}1718def get_order(order_id: OrderID) -> dict:19 return {"id": order_id}2021user_id = UserID(123)22order_id = OrderID(456)2324get_user(user_id) # OK25get_user(order_id) # Error! Wrong type26get_user(123) # Error! Plain int2728# Runtime: NewType is just identity function29print(UserID(123)) # 123
When to use:
TypeAlias — complex types that need a name.NewType — prevent mixing semantically different types.