When using type variable as a generic parameter, it can be replaced by other type variables, which is mentioned in the Generic Alias Type (but I only found this one):
The __getitem__() method of generic containers will raise an exception to disallow mistakes like dict[str][str]:
>>> dict[str][str]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: There are no type variables left in dict[str]
However, such expressions are valid when type variables are used. The index must have as many elements as there are type variable items in the GenericAlias object’s __args__.
>>> from typing import TypeVar
>>> Y = TypeVar('Y')
>>> dict[str, Y][int]
dict[str, int]
So there is no problem with your current implementation. In the interactive interpreter, you will see:
>>> from collections.abc import Sequence
>>> from typing import TypeVar
>>> T, R = TypeVar('T'), TypeVar('R')
>>> Grid = Sequence[Sequence[T]]
>>> Grid
collections.abc.Sequence[collections.abc.Sequence[~T]]
>>> Grid[R]
collections.abc.Sequence[collections.abc.Sequence[~R]]
Mypy will also correctly analyze them:
from collections.abc import Sequence, Iterable
from typing import TypeVar
T = TypeVar('T')
Grid = Sequence[Sequence[T]]
def columns(grid: Grid[T]) -> Iterable[list[T]]:
return ([row[i] for row in grid] for i in range(len(grid[0])))
c1: Iterable[list[int]] = columns([[1, 2, 3]]) # pass
c2: Iterable[list[int]] = columns([[4, 5, '6']])
# List item 2 has incompatible type "str"; expected "int" (13:42)
Sequence[Sequence[T]][R]will getSequence[Sequence[R]].