Mypy: define function working on every children of a TypedDict

Viewed 22

I have a typing question regarding TypedDicts. I want to define an abstract class with a "foo" method, accepting any dict with the key "a". And I want to define concrete classes implementing the abstract class, with a foo method accepting dicts with "a" and "b" for the first class and "a" and "c" for the second one. I Implemented it as displayed hereunder. However mypy returns the following error in both cases

Argument 1 of "foo" is incompatible with supertype "AbstractClass"; supertype defines the argument type as "DictWithA"

I tried workarounds with TypeVar("T", bound=DictWithA) or just Type[DictWithA] but did not manage to make it work.

from abc import ABC
from typing import TypedDict

class DictWithA(TypedDict):
    a: bool

class DictWithAandB(DictWithA):
    b: int

class DictWithAandC(DictWithA):
    c: int

class AbstractClass(ABC):
    def foo(self, bar: DictWithA) -> int:
        raise NotImplementedError()

class ConcreteClassB(AbstractClass):
    def foo(self, bar: DictWithAandB) -> int:
        return bar["b"] if bar["a"] else 0

class ConcreteClassC(AbstractClass):
    def foo(self, bar: DictWithAandC) -> int:
        return bar["c"] if bar["a"] else 2
1 Answers

Read up on covariance and contravariance, but in short b = ConcreteClassB() is an AbstractClass and so b.foo should accept any DictWithA. However, your method definition doesn't accept any DictWithA: passing da = DictWithA(0) as b.foo(da) won't work. That's what the error message means.

In

class X:
   def f(a : A, ...) -> ...:
       ...

class Y(X):
   def f(a : B, ...) -> ...:
       ...

B must be a superclass of A. It's the opposite to how return types work.

Related