Introduction to Typing Extensions
The typing-extensions
module is a powerful library that provides backport compatibility for modern type hints introduced in newer versions of Python. With Python’s growing focus on static type checking, this library enables developers to use advanced typing features even in older Python versions.
Let’s dive into its dozens of useful APIs with practical examples.
1. Literal
The Literal
type is useful when you want to restrict a variable to specific values.
from typing_extensions import Literal def get_status(status: Literal["success", "error", "pending"]) -> str: return f"The status is: {status}" print(get_status("success")) # Valid # print(get_status("unknown")) # Throws a type error
2. TypedDict
TypedDict allows you to create dictionary-like structures with type annotations for keys and values.
from typing_extensions import TypedDict class User(TypedDict): id: int name: str email: str user: User = {"id": 1, "name": "John", "email": "john@example.com"} print(user)
3. Final
The Final
modifier can be used to declare that a variable or method should not be overridden.
from typing_extensions import Final PI: Final = 3.14159 # PI = 3.14 # Throws a type error
4. @runtime_checkable
The @runtime_checkable
decorator allows interfaces and protocols to be used for runtime type checks.
from typing_extensions import Protocol, runtime_checkable @runtime_checkable class MyProtocol(Protocol): def execute(self) -> None: pass class MyClass: def execute(self) -> None: print("Executing...") obj = MyClass() print(isinstance(obj, MyProtocol)) # True
5. Annotated
The Annotated
type lets you add metadata to a type for better documentation or runtime processing.
from typing_extensions import Annotated def process_data(data: Annotated[int, "Positive value only"]) -> None: assert data > 0, "Value must be positive" print(f"Processing {data}") process_data(42)
6. Self
The Self
type lets you annotate methods that return instances of their own class.
from typing_extensions import Self class FluentBuilder: def __init__(self): self.value = "" def append(self, text: str) -> Self: self.value += text return self def build(self) -> str: return self.value builder = FluentBuilder() result = builder.append("Hello").append(", World!").build() print(result)
7. Example App Using Typing Extensions APIs
Let’s create a simple library catalog app using the TypedDict
, Literal
, and other features introduced above.
from typing_extensions import TypedDict, Literal, Annotated class Book(TypedDict): id: int title: str author: str status: Literal["available", "borrowed"] def add_book(catalog: list[Book], book: Book) -> None: catalog.append(book) def find_books_by_author(catalog: list[Book], author: str) -> list[Book]: return [book for book in catalog if book["author"] == author] def check_book_status(book: Book) -> str: return f"Book '{book['title']}' is {book['status']}." # Create a sample catalog catalog: list[Book] = [] add_book(catalog, {"id": 1, "title": "1984", "author": "George Orwell", "status": "available"}) add_book(catalog, {"id": 2, "title": "Brave New World", "author": "Aldous Huxley", "status": "borrowed"}) # Search for books by author orwell_books = find_books_by_author(catalog, "George Orwell") print(orwell_books) # Check book status print(check_book_status(catalog[0]))
This example demonstrates how TypedDict
, Literal
, and other APIs work together to provide type safety, clarity, and functionality to Python programs.
Start using typing-extensions in your projects today and experience the power of modern type annotations!