Identity type alias

How do I make a type IdentityType so that IdentityType[T] is synonymous with T?

Like this:

from typing import TypeAlias, TypeVar, reveal_type

type IdentityType[T] = T  # Python 3.12 only

T = TypeVar("T")
IdentityType2: TypeAlias = T  # works on older versions

def f(x: IdentityType[int], y: IdentityType2[int]):
    reveal_type(x)  # int
    reveal_type(y)  # int

(Pyright playground)

2 Likes

Thanks!

I have a second question while I’m at it: how do I make TakeFirst[S, T] which is synonymous with S?

I guess it’s clear how to do it in Python 3.12: type X[S, T] = S. But what about in Python 3.11?

I can’t think of a way to do it without the type statement.

Yeah I was looking for ways to use T in an expression but in a way that T doesn’t actually matter but I couldn’t see a way to do this. The type keyword seems pretty great.

Maybe there could be some trick with metaclasses? Something like:

class Test(type, Generic[S]):
    def __new__(cls, name, bases, classdict) -> S:
        ...

class A(metaclass=Test[S], Generic[S, T]):
    ...

But mypy is not happy with this unreasonable hack…

Incompatible return type for "__new__" (returns "int", but must return a subtype of "type")

For instance even in the following it doesn’t realize that A is 5:

class Test(type):
    def __new__(cls: Any, name: Any, bases: Any, classdict: Any) -> int:
        return 5

class A(metaclass=Test):
    ...

Thanks again for your help @Jelle!

Here’s a way to do it in 3.11,

from typing import TypeVar
from typing_extensions import TypeAliasType

S = TypeVar('S')
T = TypeVar('T')

X = TypeAliasType("X", S, (S, T))

Same idea as type statement just using backport.

Thanks @mdrissi that’s exactly what I was looking for!

I’m having trouble getting TypeAliasType to work with mypy. I have the following source code:

from typing import TypeVar
from typing_extensions import TypeAliasType

S = TypeVar("S")

Identity = TypeAliasType("Identity", S, type_params=(S,))

mypy gives:

file.pyi:7: error: Argument "type_params" to "TypeAliasType" has incompatible type "tuple[object]"; expected "tuple[typing_extensions.TypeVar | ParamSpec | TypeVarTuple, ...]"  [arg-type]

With the following versions:

$ mypy --version
mypy 1.7.1 (compiled: yes)
$ python -c  'from importlib.metadata import version; print(version("typing-extensions"))'
4.8.0
$ python --version
Python 3.11.6

Oh I see, this is a mypy TODO:

PEP 695 was accepted, and it looks like it will make it into Python 3.12. This PEP adds support for a new type parameter syntax for generic classes and methods. It also adds a new syntax for type aliases (both generic and not).


Here is a rough task list associated with this work:

  • Add support for functional form of TypeAliasType, supported for backward compatibility; see this section of PEP for details

Yeah, to my knowledge, mypy hasn’t started to add support for PEP 695 yet. If you want to use the PEP 695 functionality, it’s fully supported in pyright.

Code sample in pyright playground