ruff/crates/ty_python_semantic/resources/mdtest/annotations/annotated.md
David Peter 238f151371
[ty] Add support for Optional and Annotated in implicit type aliases (#21321)
## Summary

Add support for `Optional` and `Annotated` in implicit type aliases

part of https://github.com/astral-sh/ty/issues/221

## Typing conformance changes

New expected diagnostics.

## Ecosystem

A lot of true positives, some known limitations unrelated to this PR.

## Test Plan

New Markdown tests
2025-11-10 10:24:38 +01:00

2.5 KiB

Annotated

Annotated attaches arbitrary metadata to a given type.

Usages

Annotated[T, ...] is equivalent to T: All metadata arguments are simply ignored.

from typing_extensions import Annotated

def _(x: Annotated[int, "foo"]):
    reveal_type(x)  # revealed: int

def _(x: Annotated[int, lambda: 0 + 1 * 2 // 3, _(4)]):
    reveal_type(x)  # revealed: int

def _(x: Annotated[int, "arbitrary", "metadata", "elements", "are", "fine"]):
    reveal_type(x)  # revealed: int

def _(x: Annotated[tuple[str, int], bytes]):
    reveal_type(x)  # revealed: tuple[str, int]

Parameterization

It is invalid to parameterize Annotated with less than two arguments.

from typing_extensions import Annotated

# error: [invalid-type-form] "`typing.Annotated` requires at least two arguments when used in a type expression"
def _(x: Annotated):
    reveal_type(x)  # revealed: Unknown

def _(flag: bool):
    if flag:
        X = Annotated
    else:
        X = bool

    # error: [invalid-type-form] "`typing.Annotated` requires at least two arguments when used in a type expression"
    def f(y: X):
        reveal_type(y)  # revealed: Unknown | bool

# error: [invalid-type-form] "`typing.Annotated` requires at least two arguments when used in a type expression"
def _(x: Annotated | bool):
    reveal_type(x)  # revealed: Unknown | bool

# error: [invalid-type-form] "Special form `typing.Annotated` expected at least 2 arguments (one type and at least one metadata element)"
def _(x: Annotated[()]):
    reveal_type(x)  # revealed: Unknown

# error: [invalid-type-form]
def _(x: Annotated[int]):
    # `Annotated[T]` is invalid and will raise an error at runtime,
    # but we treat it the same as `T` to provide better diagnostics later on.
    # The subscription itself is still reported, regardless.
    # Same for the `(int,)` form below.
    reveal_type(x)  # revealed: int

# error: [invalid-type-form]
def _(x: Annotated[(int,)]):
    reveal_type(x)  # revealed: int

Inheritance

Correctly parameterized

Inheriting from Annotated[T, ...] is equivalent to inheriting from T itself.

from typing_extensions import Annotated
from ty_extensions import reveal_mro

class C(Annotated[int, "foo"]): ...

reveal_mro(C)  # revealed: (<class 'C'>, <class 'int'>, <class 'object'>)

Not parameterized

from typing_extensions import Annotated
from ty_extensions import reveal_mro

# At runtime, this is an error.
# error: [invalid-base]
class C(Annotated): ...

reveal_mro(C)  # revealed: (<class 'C'>, Unknown, <class 'object'>)