Search code examples
pythonmypypython-typing

Inheriting Generic classes with restricted TypeVar


Consider a simple pair of generic classes:

T = TypeVar("T", str, int)

class Base(Generic[T]):
    def __init__(self, v: T):
        self.v: T = v

    @property
    def value(self) -> T:
        return self.v

class Child(Base[T]):
    def __init__(self, v: T):
        super().__init__(v)

x = Child(123)
reveal_type(x.value)

While using T = TypeVar("T") works as expected. The restricted TypeVar as shown yields the following errors:

error: Argument 1 to "__init__" of "Base" has incompatible type "str"; expected "T"
error: Argument 1 to "__init__" of "Base" has incompatible type "int"; expected "T"
note: Revealed type is 'builtins.int*'

Note that reveal_type still works.

Another difference, is that the restricted TypeVar requires the type annotation for self.v assignment whereas the unrestricted does not.

In the full use-case, I actually have Callable[[Any], T], but the issue is the same.

This is with mypy 0.910 and Python 3.9.7.


Solution

  • Bounding T to an Union[int,str] should do the job:

    T = TypeVar("T", bound=Union[str, int])
    
    
    class Base(Generic[T]):
    
        def __init__(self, v: T):
            self.v: T = v
    
        @property
        def value(self) -> T:
            return self.v
    
    
    class Child(Base[T]):
    
        def __init__(self, v: T):
            super().__init__(v)
    
    
    x = Child(123)
    reveal_type(x.value)
    y = Child('a')
    reveal_type(y.value)