MyPy does not allow passing class of the TypedDict as an argument to a function

Viewed 463

Following code:

class A(TypedDict):
    abc: str


class B(TypedDict):
    xyz: str


def func(dict_class: Union[type[A], type[B]]) -> None:
    print(dict_class.__annotations__)


func(A)

results in a following MyPy error:

error: Argument 1 to "func" has incompatible type "Type[A]"; expected "Union[Type[A], Type[B]]"

Is there any other way to tell MyPy that the dict_class argument can only be of specified typed dicts types? I know that I can change the type hints to something more generic so that the MyPy won't complain but I really wouldn't want to.

What's more important is that the PyCharm IDE seems to work with this example all right. Is it a MyPy bug then?

1 Answers

This is a known issue when using the TypedDict which is mentioned for example here.

More simple example:

from typing import TypedDict

D = TypedDict('D', {})
x: type[D] = D  # error

Produce unobvious message:

error: Incompatible types in assignment (expression has type "Type[D]", variable has type "Type[D]")

@ilevkivskyi explains this behaviour here this way:

Yeah, this doesn't work because Type[...] is not supposed to work with anything but classes, unions of classes, and Any, see PEP 484.

It seems to me it might be possible to relax this limitation to some extent, but first of all we should fix the errors message, which is cryptic.

You can read more about using the TypedDict in PEP 589. @serhiy.storchaka briefly described it here as follows:

TypeDict is a callable, it can be used as

Point2D = TypedDict('Point2D', x=int, y=int, label=str)

It can also be used as a base in class definition, but is is not a class itself. It does not occur in __bases__ of the created class, and it cannot be used in isinstance() and issubclass() checks. It is just yet one weird way to customize class creation.

Related