I have a slightly complicated type situation where the minimum reproducible version I could come up with looks like this:
from __future__ import annotations
from typing import TypeVar
T = TypeVar("T")
class MyClass(list[T]):
def method(self, num: int) -> MyClass[MyRecursiveType]:
if num == 1:
return MyClass([1, 2, 3])
return MyClass([self, 1, 2, 3])
MyRecursiveType = int | MyClass["MyRecursiveType"]
My thinking here is that MyClass.method(...) should return an instance of MyClass, and that it should contain either int or further instances of MyClass (hence the recursive type)
The issue is that if I run mypy, I get the error on L13:
error: List item 0 has incompatible type "MyClass[T]"; expected "Union[int, MyClass[MyRecursiveType]]" [list-item]
I can get mypy to stop complaining by adding my T
to the union in MyRecursiveType
and marking it explcitly as a TypeAlias
, like this:
from __future__ import annotations
from typing import TypeAlias, TypeVar
T = TypeVar("T")
class MyClass(list[T]):
def method(self, num: int) -> MyClass[MyRecursiveType]:
if num == 1:
return MyClass([1, 2, 3])
return MyClass([self, 1, 2, 3])
MyRecursiveType: TypeAlias = int | T | MyClass["MyRecursiveType"]
But this doesn't feel quite correct, what would be a more correct solution?
EDIT:
Updating to make example more aligned to my real code, since I did not capture the full issue I think:
from __future__ import annotations
from typing import TypeVar
T = TypeVar("T")
class MyClass(list[T]):
pass
class MySubClassOne(MyClass[T]):
def one(self, val: int | MyClass):
if val == 1:
return MySubClassOne([1, 2, 3])
return MySubClassOne([self, 1, 2, 3])
def two(self, val: int | MyClass):
if val == 1:
return MySubClassTwo([1, 2, 3])
return MySubClassTwo([self, 1, 2, 3])
class MySubClassTwo(MyClass[T]):
def one(self, val: int | MyClass):
if val == 2:
return MySubClassOne([1, 2, 3])
return MySubClassOne([self, 1, 2, 3])
def two(self, val: int | MyClass):
if val == 2:
return MySubClassTwo([1, 2, 3])
return MySubClassTwo([self, 1, 2, 3])
So in this example the issue is that different subclasses return each other and could contain arbitrarily deeply nested versions of one another, which I'd like to capture.