Introduction to typing-extensions
The typing-extensions
library is an essential tool for any Python developer looking to harness the full power of type hinting. It provides backports of new type hinting features from later versions of Python that can be used in earlier versions. This makes it easier to maintain modern, type-safe Python code. Below, we explore dozens of useful APIs from the typing-extensions
library with helpful code snippets.
Dozens of Useful APIs from typing-extensions
1. TypedDict
TypedDict
allows for more precise type hinting for dictionaries.
from typing_extensions import TypedDict class Movie(TypedDict): title: str year: int movie: Movie = {'title': 'Inception', 'year': 2010}
2. Literal
The Literal
type allows you to specify that a function parameter must be a specific value.
from typing_extensions import Literal def get_status(status: Literal['open', 'closed']) -> str: return f'Status is {status}' status = get_status('open')
3. Final
Final
is used to denote that a variable or method should not be overridden.
from typing_extensions import Final MAX_ITEMS: Final = 100
4. TypedDict with Total
You can use the Total
argument with TypedDict
to indicate whether a dictionary needs to include all keys.
from typing_extensions import TypedDict class Movie(TypedDict, total=False): title: str year: int movie: Movie = {'title': 'Interstellar'}
5. Protocol
Protocol
is used to define structural subtyping in Python.
from typing_extensions import Protocol class Greetable(Protocol): def greet(self) -> str: ... class Person: def greet(self) -> str: return "Hello" def greet_all(greetables: list[Greetable]) -> None: for g in greetables: print(g.greet()) people = [Person()] greet_all(people)
6. runtime_checkable
runtime_checkable
decorator can be used to enable isinstance
checks against protocols.
from typing_extensions import Protocol, runtime_checkable @runtime_checkable class Greetable(Protocol): def greet(self) -> str: ... class User: def greet(self) -> str: return "Hi" user = User() assert isinstance(user, Greetable)
7. NewType
NewType
allows creating distinct types for better static type checking.
from typing_extensions import NewType UserID = NewType('UserID', int) def get_user_name(user_id: UserID) -> str: return f'User_{user_id}' user_id = UserID(42) user_name = get_user_name(user_id)
App Example Using typing-extensions
Let’s build a simple user management application using some of the APIs discussed above.
from typing_extensions import TypedDict, Literal, Final, Protocol, runtime_checkable, NewType UserID = NewType('UserID', int) MAX_USERS: Final = 100 class User(TypedDict): id: UserID name: str class Greetable(Protocol): def greet(self) -> str: ... @runtime_checkable class UserGreetable(Greetable, Protocol): name: str def add_user(users: list[User], user: User) -> None: if len(users) < MAX_USERS: users.append(user) else: raise ValueError("Max users limit reached") def greet_user(user: UserGreetable) -> str: return f'Hello, {user.name}' def user_status(user: User, status: Literal['active', 'inactive']) -> str: return f'User {user["name"]} is {status}' existing_users: list[User] = [] new_user: User = {'id': UserID(1), 'name': 'Alice'} add_user(existing_users, new_user) for user in existing_users: print(greet_user(user)) print(user_status(user, 'active'))