User defined type-level operators works, are they legal?
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 20.6k
- Forks
- 3.3k
- PR merge metrics
- PR metrics pending
Description
While looking for a workaround about the lack of extensible typed records, found some approaches that works, but then I realized, I'm using quite a few type level operators for that, are they legal?
My use case is too cumbersome and irrelevant to explain, but a simpler self-explanatory example:
Retrieving inner type of Awaitable:
from typing import Awaitable, Type, TypeVar
A = TypeVar("A")
class typeofMeta(type):
def __getitem__(cls, value: A) -> Type[A]: raise NotImplementedError
class AwaitedMeta(type):
def __getitem__(cls, value: Type[Awaitable[A]]) -> Type[A]: raise NotImplementedError
class typeof(metaclass=typeofMeta): ...
class Awaited(metaclass=AwaitedMeta): ...
async def add(a: int, b: int) -> int:
return a + b
coro = add(1, 2)
reveal_type(Awaited[typeof[coro]])
# Revealed type is "Type[builtins.int]"
By defining a __getitem__ at class level I can do whatever with the types and make native-looking type operators. After that I noticed the use of @_SpecialForm in typing internals, but no mention that I could find in docs if this use can be replicated by developers. So I'm wondering if it's safe to rely on this kind of stuff, it enables a lot of nice composition patterns and zero-cost abstractions structures, like is common is TS.
Here are a few more typescript util clones, full implementation in gist:
Type-Level if-else
reveal_type(InstanceType[If[True, int, str]])
# Revealed type is 'builtins.int'
reveal_type(InstanceType[If[False, int, str]])
# Revealed type is 'builtins.str'
Get precise type of an object
def add(a: int, b: int) -> int: return a + b
reveal_type(typeof[add])
# Revealed type is 'def (builtins.int, builtins.int) -> builtins.int'
reveal_type(Type[add]) # with builtin `Type` get down to object
# Revealed type is builtins.object'
Get instance type from a class
class Box(Generic[A]):
value: A
reveal_type(InstanceType[Box[int]])
# Revealed type is 'Box[builtins.int]'
Get return type of a callable
def add(a: int, b: int) -> int: return a + b
reveal_type(ReturnType[add])
# Revealed type is 'builtins.int'
Get parameter typle of a callable
def add(a: int, b: int) -> int: return a + b
reveal_type(Parameters[add])
# Revealed type is 'Tuple[builtins.int, builtins.int]'
Get inner type of an Awaitable
async def add(a: int, b: int) -> int: return a + b
coro = add(1, 2)
reveal_type(Awaited[typeof[coro]])
# Revealed type is "Type[builtins.int]"
Get item type of an iterable
reveal_type(ItemOf[list[int]])
# Revealed type is 'Type[builtins.int]'
Get key type of a Mapping
reveal_type(keyof[dict[str, int]])
# Revealed type is 'builtins.str'
So, are those legal?
Searched but couldn't find docs on it. I do remember seeing @gvanrossum commenting on some issue (couldn't find it now) that mypy is being conservative about allowing user-defined type operators, so I'm a bit afraid of using those.
In pyright it's even crazier, a lot of tricks with tuples are possible with Head[Unpack[Vars]] and Tail[Unpack[Vars]], plus some typevar bounding behaviour that made me notice even higher kinded types implementation is possible using the Lightweight higher-kinded polymorphism encoding, or maybe even a small type-level implementation of lisp
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the user-defined operators and reveal_type examples in the issue, then compare them with mypy/typeshed/stdlib/typing.pyi and the linked pyright behavior. Determine whether the documented typing rules address these constructs and what specific documentation gap remains; the issue is complete only when the legality and supported usage are documented or clearly resolved.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- devtools
- Issue type
- Documentation
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100