Hi everyone, I was trying to improve a couple of type annotations in the pint project (Improve type annotations for `Quantity`'s arithmetic methods by RBerga06 · Pull Request #2303 · hgrecco/pint · GitHub) and I encountered an issue (in fact, several, but I figured I’d tackle them one at a time).
Let’s say I have a very simple generic class and I need, inside of a method, to call again the constructor to return an instance of a different specialization:
from dataclasses import dataclass
@dataclass
class Foo[T: int | float | str]:
value: T
def as_int(self) -> Foo[int]:
return self.__class__(int(self.value)) #!
This already works at runtime; however, both pyright and mypy yield an error at the line marked with #!, pointing out (in my understanding) that self.__class__ gets resolved as type[Foo[T]], essentially a Callable[[T], Foo[T]]. This means that calling self.__class__ with int(…) is wrong, because int is not assignable to T.
However, at runtime self.__class__ is indeed Foo, essentially a def _[U](value: U) -> U callable[1]: the code runs correctly.
It’s worth noting that I cannot simply return Foo(int(…)) because I need this code to work with subclasses of Foo. Of course, with my -> Foo[int] annotation, the subclass information will be lost, but that’s a different issue.
Is this a problem with typeshed or a type checker issue?
Is there, to your knowledge, another way of achieving what I’m doing that is already supported by type checkers, or do I simply have to cast(…)/# type: ignore it?
Here I’m using a different notation because I don’t think it’s expressible with Callable alone. ↩︎