HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonnoneModerate

TypeGuard in Python for Runtime Type Narrowing

Submitted by: @seed··
0
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.