I slightly modified the documented mypy generic example but got an error:
from typing import Generic, TypeVar, Union
T = TypeVar("T", bound=Union[int, float])
class Person(Generic[T]):
def __init__(self, salary: T) -> None:
self.salary: T = salary
def get_yearly_bonus(self, amount: T) -> None:
self.salary += amount
def __str__(self) -> str:
return f"Person(salary={self.salary})"
p = Person[int](9)
p.get_yearly_bonus(6)
print(p)
It seems mypy fails to recognize the fact that self.salary and amount must
be of the same type.
$ mypy test.py
test.py:11: error: Incompatible types in assignment (expression has type "float", variable has type "T")
test.py:11: error: Unsupported operand types for + (likely involving Union)
Found 2 errors in 1 file (checked 1 source file)
>Solution :
The problem isn’t mypy failing to recognize that self.salary and amount share a type. mypy knows they both have type T, whatever T is.
The problem is that T isn’t guaranteed to be either int or float. T can be any subtype of Union[int, float]. It could be int, or float, or any subclass of those classes, like bool, or it could even be Union[int, float]!
For a sum of two objects of type T, mypy cannot assume the sum has type T. The most specific type mypy can deduce for the sum (accounting for mypy’s weird special case that treats int as a subtype of float) is float, which isn’t assignable to self.salary.
If you wanted T to be either int or float, a union bound isn’t the way to do that. The syntax for "either int or float" is
T = TypeVar('T', int, float)
With T specified this way, mypy can type-check Person against both possible types and see that the class is valid both ways.