Expected type 'List[A]' (matched generic type 'List[_T]'), got 'List[B]' instead on correctly typed lists
from typing import List
class Base(object):
pass
class A(Base):
pass
class B(Base):
pass
a: List[A] = []
b: List[B] = []
c: List[Base] = a + b
I am getting Expected type 'List[A]' (matched generic type 'List[_T]'), got 'List[B]' instead
on b
.
How do I get correct warnings, as obviously the types are fine.
These types are not fine. List
is invariant, meaning that a List[X]
is not a substitute for List[Y]
unless X
and Y
are exactly equal. Similarly, A <: Base
does not imply List[A] <: List[Base]
and likewise for B
.
PEP 484: Covariance and contravriance
[...]
By default generic types are considered invariant in all type variables, which means that values for variables annotated with types likeList[Employee]
must exactly match the type annotation -- no subclasses or superclasses of the type parameter (in this exampleEmployee
) are allowed.
While it is possible to re-interpret the types for this operation, this is not unambiguous. A conservative type checker will reject the operation instead of guessing.
A mutable container such as List
is invariant because elements can be both inserted into (contravariant) and taken from (covariant) the list. If mutability is not required, using an immutable Sequence provides valid type annotation:
from typing import Sequence
a: Sequence[A] = []
b: Sequence[B] = []
c: Sequence[Base] = [*a, *b]
If mutability is desired, one can explicitly enumerate all the types to be found in the List
. This pre-emptively widens the elements to be expected in the list, even if each individual list actually contains only one type.
a: List[Union[A, B]] = []
b: List[Union[A, B]] = []
c: List[Union[A, B]] = a + b
Pre-emptively widening the type of the operands may be undesirable or impossible. Alternatively, one can cast
them at the site of usage.
a: List[A] = []
b: List[B] = []
c: List[Union[A, B]] = cast(List[Union[A, B]], a) + cast(List[Union[A, B]], a)
Note that cast
effectively disables type checking for the cast'ed value. Only use it in cases that are known to be correct.