patternpythonnoneModerate
TypeGuard in Python for Runtime Type Narrowing
Viewed 0 times
Python 3.10+
TypeGuardtype narrowingruntime type checktype predicateisinstance
Problem
Functions that check runtime types return bool, so type checkers don't narrow the type in the calling code — the value is still typed as the broad type after an isinstance check in a separate function.
Solution
Use TypeGuard as the return annotation to narrow types in calling code.
from typing import TypeGuard
def is_string_list(val: list[object]) -> TypeGuard[list[str]]:
return all(isinstance(x, str) for x in val)
def process(items: list[object]) -> None:
if is_string_list(items):
# items is list[str] here — not list[object]
joined = ', '.join(items) # OK — no type error
print(joined.upper())
# Without TypeGuard, items would still be list[object] inside the if block
# and ', '.join(items) would be a type error
# Practical example: API response validation
def is_user_dict(data: object) -> TypeGuard[dict[str, str]]:
return (
isinstance(data, dict)
and all(isinstance(k, str) and isinstance(v, str) for k, v in data.items())
)Why
TypeGuard tells the type checker: 'if this function returns True, narrow the first argument to the specified type'. It's the Python equivalent of TypeScript's 'value is Type' predicate.
Gotchas
- TypeGuard only narrows the type in the True branch — the False branch is not narrowed.
- The type checker trusts your TypeGuard implementation — an incorrect predicate creates unsound types.
- TypeGuard was added in Python 3.10; use typing_extensions for earlier versions.
Revisions (0)
No revisions yet.