I want to create a generic type A[T]
that acts exactly like T
, except that I can tell at runtime that the type is in fact A[T]
and not T
.
I tried
class A(Generic[T], T):
pass
but that does not seem to work, as mypy complains, for example, that A[str]
is of type object
.
As an example, I want something like this to pass type checking:
def f(s: A[str]):
return re.findall('foo|bar', s)
But still be somehow able to tell A[str]
from str
at runtime, when I get a variable of that type or inspect the function signature.
Is there a way to do this?
0
One way is to use a generic type alias that returns its only type argument:
(playground links: Mypy, Pyright)
type A[T] = T
def f(s: A[str]) -> None:
reveal_type(s) # str
re.findall('foo|bar', s) # fine
f('') # fine
>>> type(inspect.get_annotations(f)['s'])
<class 'types.GenericAlias'>
In older Python versions, use typing_extensions.TypeAliasType
:
from typing import TypeVar
from typing_extensions import TypeAliasType
T = TypeVar('T')
A = TypeAliasType('A', T, type_params = (T,))
# ^^^^^^^^^^^^^^^^^^ This part is optional
Another way is to use Annotated[]
:
(playground links: Mypy, Pyright)
from typing import Annotated
# There must be at least two arguments
def f(s: Annotated[str, 'Whatever']) -> None:
reveal_type(s) # str
re.findall('foo|bar', s) # fine
f('') # fine
>>> type(inspect.get_annotations(f)['s'])
<class 'typing._AnnotatedAlias'>
The latter is preferred, especially if you want to attach metadata to the type in question.
6