Annotating the `Self` type in a `TypedDict` with the Alternative Syntax

Viewed 50

I have a TypedDict which I am using to represent a query. This query is recursive, so one of the keys can contain the same type as the parent. If I use the Self type, it looks like this:

from typing import TypedDict, Self, Iterable

class Query(TypedDict):
    and_: Iterable[Self]
    or_: Iterable[Self]

However, I don't want to have this underscore after and_: the real key should just be and. So then I have to represent this using the function call syntax, since and is not a valid identifier in Python:

from typing import TypedDict, Self, Iterable

Query = TypedDict("Query", {
    "and": Iterable[Self]
    "or": Iterable[Self]
}

Except that Self is not valid outside of a class context, so now mypy gives me:

test.py:4: error: Variable "typing_extensions.Self" is not valid as a type

Now, I could also try the old fashioned way of writing Self, as described here. However this method relies on being able to annotate the type of self with a TypeVar:

TShape = TypeVar("TShape", bound="Shape")

class Shape:
    def set_scale(self: TShape, scale: float) -> TShape:
        self.scale = scale
        return self

Unfortunately I can't do this here either, since I'm not using a class.

Lastly, it might seem like I could make my TypedDict generic, like this:

from typing_extensions import TypeAlias, TypedDict, Self
from typing import TypeVar

T = TypeVar("T", bound="Query")

Query = TypedDict("Query", {
    "and": T,
    "or": T
})

But again, because I'm not using a class, mypy complains:

test.py:7: error: Type variable "test.T" is unbound
test.py:7: note: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class)
test.py:7: note: (Hint: Use "T" in function signature to bind "T" inside a function)

Is there any way to refer to the Self type when using the non-class syntax for TypedDict?

0 Answers
Related