I would like to make a function which, given a variable x of type T makes an object of type A[T] and passes x to its constructor (and a few extensions on this). I understand that we can do “type narrowing” on variables, i.e., we can determine that x is of some narrower type Q with isinstance, or TypeGuard or TypeIs, and then a type checker will know that x is of type Q. However, it seems that if x is of type T and we check with isinstance (or TypeGuard or TypeIs) that x is of a subtype of T, that doesn’t impact what current type checkers think about type T.
class A[T]:
def __init__(self, x:T):
self.x=x
class B(A[int]):
pass
def failing_1[T](x:T) -> A[T] | None:
if isinstance(x,int):
return A[T](x) # Argument 1 to "A" has incompatible type "int"; expected "T"
return A[T](x)
def failing_2[T](x:T) -> A[T]:
if isinstance(x,int):
return B(x) # Incompatible return value type (got "B", expected "A[T]")
return A[T](x)
def working[T](x:T) -> A[T]:
return A[T](x)
In the above, in failing_1, mypy sees the isinstance, and concludes that x is of type int. mypy forgets that x is of type T too, and what is clearly allows gives a mypy error. The function “working” illustrates that without the isinstance there is no confusion and the same code, applicable on the same input, works well.
In fact, I would also like to do something like failing_2, i.e., if we know that x is of type int (hence T=int) and that B is a subclass of A[int], then returning an object of type B where A[T]=A[int] is expected should be allowed. I tried to define explicitly T as covariant, but that doesn’t help.
The same problems arises when running pyright rather than mypy. (hence this is not likely to be a bug)
More generally, this kind of problem arises in several forms when I want to tell the type checker that two objects have related type parameters, e.g., as here (T vs A[T]), but also (x:T1 and y:T2 with T1 = A[T2])
Hence my question: do I miss some existing typing mechanism or does the current type system not allow to narrow type parameters (rather than just variables) ?