Introduction to Typing Extensions
The typing-extensions
Python library offers support for new type-hinting features introduced in more recent versions of Python. These features can be used with older versions of Python, making it a vital tool for developers aiming to maintain compatibility while adopting the latest typing improvements. In this article, we’ll dive into the most useful APIs provided by typing-extensions
and demonstrate how you can leverage them with examples.
1. Setup for Typing Extensions
Before we dive into code snippets, ensure you have the library installed. You can add it to your Python environment using:
pip install typing-extensions
2. Popular APIs in Typing Extensions
Below is a list of useful APIs provided by typing-extensions
, along with their explanations and examples:
2.1. Literal
The Literal
type is used to explicitly define a set of constant values a variable can hold.
from typing_extensions import Literal def get_status_color(status: Literal["success", "error", "loading"]) -> str: if status == "success": return "green" elif status == "error": return "red" elif status == "loading": return "yellow" else: raise ValueError("Invalid status") print(get_status_color("success")) # Output: green
2.2. TypedDict
TypedDict
is a way to represent dictionaries with a fixed set of keys and defined types.
from typing_extensions import TypedDict class User(TypedDict): id: int name: str is_active: bool user: User = {"id": 1, "name": "Alice", "is_active": True} print(user["name"]) # Output: Alice
2.3. Protocol
The Protocol
type is used for defining structural subtyping.
from typing_extensions import Protocol class Greeter(Protocol): def greet(self, name: str) -> str: ... class FriendlyGreeter: def greet(self, name: str) -> str: return f"Hello, {name}!" def greet_person(greeter: Greeter, name: str) -> None: print(greeter.greet(name)) friendly = FriendlyGreeter() greet_person(friendly, "Alice") # Output: Hello, Alice!
2.4. Annotated
Annotated
allows attaching metadata to types.
from typing_extensions import Annotated def process_data(age: Annotated[int, "Age in years"]) -> None: print(f"Processing data for age: {age}") process_data(25) # Output: Processing data for age: 25
2.5. Working with Final
The Final
type declares variables that should not be reassigned.
from typing_extensions import Final PI: Final[float] = 3.14159 def calculate_circumference(radius: float) -> float: return 2 * PI * radius print(calculate_circumference(5)) # Output: 31.4159
3. Building a Simple Application
Let us now create a simple task tracking application using typing-extensions
features.
from typing_extensions import TypedDict, Literal class Task(TypedDict): id: int description: str status: Literal["pending", "in-progress", "completed"] def create_task(task_id: int, description: str) -> Task: return {"id": task_id, "description": description, "status": "pending"} def update_task_status(task: Task, new_status: Literal["pending", "in-progress", "completed"]) -> Task: task["status"] = new_status return task # Create a task task = create_task(1, "Write typing-extensions blog post") print(task) # Update task status task = update_task_status(task, "in-progress") print(task)
In this app example, we have shown how TypedDict
and Literal
can help define clear type constraints for tasks.
4. Conclusion
typing-extensions
is a must-have library for Python developers embracing type hints and annotations. From Literal
to Protocol
, it includes practical tools to improve type safety and readability in your codebase.