-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
Feature
It would be nice if the following worked:
from typing import Annotated, List, TypeVar
T = TypeVar("T")
def convert(val: object, ty: type[T]) -> T:
raise NotImplementedError
reveal_type(convert([1], list[int]))
reveal_type(convert([1], List[int]))
reveal_type(convert(None, int | None))
reveal_type(convert(1, Annotated[int]))
Currently the first 2 calls type check as expected, but the following 2 calls fail with
type_t.py:10: note: Revealed type is "<nothing>"
type_t.py:10: error: Argument 2 to "convert" has incompatible type "UnionType"; expected "type[<nothing>]" [arg-type]
type_t.py:11: note: Revealed type is "<nothing>"
type_t.py:11: error: Argument 2 to "convert" has incompatible type "object"; expected "type[<nothing>]" [arg-type]
Technically int | None
is not a type object, but neither are List[int]
and list[int]
. However, they are type specifications recognized by type checkers, and it is clear what the meaning of the call is.
Another option is to provide a new type like TypeSpec[T]
to use for cases where the value is not necessarily a type object but is a valid type specification, if extending type
is deemed not appropriate. The difference may be too subtle, though, and type
already accepts some values which are not types per the example above.
If this works, type checkers can remove special cases for typing.cast
function. It can be annotated simply as
def cast(typ: type[_T], val: Any) -> _T: ...