Type hinting generic function operating on type, and returning concrete value of that type

I want to type hint get function so if I call get(int), returned value type will be inferred as int.

from typing import TYPE_CHECKING

Types = int | str

mapping: dict[type[Types], Types] = {
    int: 6,
    str: 'test',
}

def get[T](t: type[T]) -> T:
    if TYPE_CHECKING:
        reveal_type(t)
    return mapping[t]

result = get(int)

if TYPE_CHECKING:
    reveal_type(result)

print(result)

When I run mypy --strict I get:

type.py:12: note: Revealed type is "type[T`-1]"
type.py:13: error: Incompatible return value type (got "int | str", expected "T")  [return-value]
type.py:13: error: Invalid index type "type[T]" for "dict[type[int] | type[str], int | str]"; expected type "type[int] | type[str]"  [index]
type.py:18: note: Revealed type is "builtins.int"

I am using python 3.12.2 and mypy 1.15.0.

The external interface of get works correctly already. But it’s internals currently cannot be typed correctly - you are going to need to use explicit casts/#type: ignore to silence the warnings.

You could also solve it by defining a polymorphic Mapping type. This way, you’ll only have to type ignore the assignment. Code sample in pyright playground

from typing import Protocol, TYPE_CHECKING

class TypeMap(Protocol):
    def __getitem__[T](self, key: type[T], /) -> T: ...
    def __setitem__[T](self, key: type[T], value: T, /) -> None: ...

mapping: TypeMap = {  # type: ignore[assignment]
    int: 6,
    str: 'test',
}

def get[T](t: type[T]) -> T:
    if TYPE_CHECKING:
        reveal_type(t)
    return mapping[t]

result = get(int)

if TYPE_CHECKING:
    reveal_type(result)

print(result)
4 Likes

I think the easiest way to understand why this flags is this slight modification:

Types = int | str
mapping: dict[type[Types], Types]  = {
    int: 6,
    str: 'test',
}

mapping = {
    # switching keys around is still valid with existing 
    # annotation dict[type[Types], Types]
    # and won't flag since the key value relationship is too simple,
    # any key type could result in any of the value types
    str: 6,
    int: 'test',
}
2 Likes

This is a commonly asked question on Stack Overflow: Type hint for a dict that maps tuples containing classes to the corresponding instances.