> ## Documentation Index
> Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Python TypeGuard

`typing.TypeGuard` is a special typing construct introduced in PEP 647 (Python 3.10) that enables user-defined type narrowing. It instructs static type checkers (such as mypy or pyright) that if a boolean-returning function evaluates to `True`, a specific argument passed to that function is guaranteed to be of the type specified within the `TypeGuard`.

At runtime, `TypeGuard[T]` behaves exactly like a standard `bool` return type annotation. Its sole purpose is to influence static flow analysis in the calling scope.

## Syntax

A function utilizing a type guard must return a boolean value and annotate its return type as `TypeGuard[TargetType]`.

```python theme={"dark"}
from typing import TypeGuard, Any

def is_string(val: Any) -> TypeGuard[str]:
    # Runtime logic that validates the type of 'val'
    return isinstance(val, str) 
```

## Type Checker Mechanics

When a static type checker encounters a function returning `TypeGuard[T]`, it applies specific narrowing rules to the calling scope based on the control flow:

1. **The `True` Branch (Positive Narrowing):** If the type guard function returns `True`, the type checker narrows the type of the passed argument to `T` within the corresponding `if` block.
2. **The `False` Branch (No Negative Narrowing):** If the type guard function returns `False`, the type checker does not perform negative narrowing. The argument retains its original, un-narrowed type in the `else` block. The type checker does not subtract the guarded type from the original type because a `TypeGuard` function can contain arbitrary runtime logic and value checks (e.g., `val.isalnum()` or `len(val) > 0`). A `False` return only implies that the specific validation failed, which does not necessarily mean the argument is strictly not of type `T`.

```python theme={"dark"}
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(data: list[object]) -> None:
    if is_string_list(data):
        # Type checker evaluates 'data' as list[str]
        print(data) 
    else:
        # Type checker evaluates 'data' as list[object]
        # It DOES NOT narrow to a type excluding list[str]
        print(data) 
```

## Technical Constraints

* **Argument Binding:** A `TypeGuard` strictly and exclusively narrows the argument bound to the **first parameter defined in the function signature**, regardless of whether the caller passes it as a positional or a keyword argument. When applied to an instance method or a class method, `TypeGuard` narrows the argument bound to the **second parameter** (the first explicit parameter immediately following `self` or `cls`). It cannot be configured to target any other parameter.
* **Implicit Trust:** Static type checkers do not verify the internal logic of the function returning the `TypeGuard`. The type checker implicitly trusts that the developer's runtime implementation accurately guarantees the type `T`. If the internal logic is flawed, it will introduce unsoundness into the type system.
* **Type Overriding:** According to PEP 647, `TypeGuard` does not require the target type `T` to be a strict subtype of the original argument's type. It allows narrowing to an entirely unrelated type hierarchy. In such cases, `TypeGuard` effectively acts as an unsafe cast in the positive branch, completely overriding the original type rather than intersecting it.

*(Note: Because `TypeGuard` allows unsafe casting to unrelated types and lacks negative narrowing in the `False` branch, Python 3.13 introduced `typing.TypeIs` via PEP 742. `TypeIs` enforces stricter type intersection, ensuring the narrowed type is a valid subtype, and allows for both positive and negative type narrowing.)*

<div
  style={{ 
display: "flex", 
justifyContent: "space-between", 
alignItems: "center", 
maxWidth: "754px", 
padding: "1rem 0",
marginBottom: "24px"
}}
>
  <span style={{ fontWeight: "bold", fontSize: "1.25rem", color: "var(--tw-prose-headings)", fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif" }}>Tired of Poor Python Skills? Fix That With Deep Grasping!</span>

  <a
    href="https://syntblaze.com"
    target="_blank"
    style={{ 
  marginLeft: "24px",
  textDecoration: "none", 
  backgroundColor: "#007AFF",
  color: "#ffffff", 
  padding: "6px 16px", 
  borderRadius: "16px",
  fontSize: "0.9rem",
  fontWeight: "600",
  textAlign: "center",
  transition: "background-color 0.2s ease"
}}
  >
    Learn More
  </a>
</div>

<div style={{ display: "flex", gap: "12px", flexWrap: "wrap" }}>
  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/skill-tracking.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=b9b0305c93bb501c9e767b5c76c88835" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/skill-tracking.png" />

  <img src="https://mintcdn.com/syntblazellc/23tyuOzaWS88qFlc/images/nuggets.png?fit=max&auto=format&n=23tyuOzaWS88qFlc&q=85&s=c86c80197299762989e9b882419b2109" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/nuggets.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/bite-sized-exercises.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=a65f9a38c37ff28ab73ed783c53c60e3" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/bite-sized-exercises.png" />
</div>

<div style={{ display: "flex", gap: "12px", flexWrap: "wrap", marginTop: "12px" }}>
  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/mastery-chain.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=748a1763454713e679260fbb95f154a2" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/mastery-chain.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/element-previews.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=242f61448ff5dd6deaaab2dccc13b507" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/element-previews.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/element-explanations.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=cf0fc1c31f9cd0fc26716781be05fbc9" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/element-explanations.png" />
</div>
