enumerate.__next__
needs more context than is available to have a return type more specific than Tuple[int, Any]
, so I believe mypy
itself would need to be modified to make the inference that enumerate(actions)
produces Tuple[int,Union[str,int]]
values.
Until that happens, you can explicitly cast the value of action
before passing it to act
.
from typing import Union, cast
StrOrInt = Union[str, int]
def process(actions: Union[list[str], list[int]]) -> None:
for pos, action in enumerate(actions):
act(cast(StrOrInt, action))
def act(action: Union[str, int]) -> None:
print(action)
You can also make process
generic (which now that I've thought of it, is probably a better idea, as it avoids the overhead of calling cast
at runtime).
from typing import Union, cast, Iterable, TypeVar
T = TypeVar("T", str, int)
def process(actions: Iterable[T]) -> None:
for pos, action in enumerate(actions):
act(action)
def act(action: T) -> None:
print(action)
Here, T
is not a union of types, but a single concrete type whose identity is fixed by the call to process
. Iterable[T]
is either Iterable[str]
or Iterable[int]
, depending on which type you pass to process
. That fixes T
for the rest of the call to process
, which every call to act
must take the same type of argument.
An Iterable[str]
or an Iterable[int]
is a valid argument, binding T
to int
or str
in the process. Now enumerate.__next__
apparently can have a specific return type Tuple[int, T]
.