Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 37 additions & 14 deletions peps/pep-0827.rst
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,9 @@ which produce aliases that have some dunder methods overloaded for
Many of the operators specified have type bounds listed for some of
their operands. These should be interpreted more as documentation than
as exact type bounds. Trying to evaluate operators with invalid
arguments will produce ``Never`` as the return. (There is some
arguments will produce an error. When this happens, the value of the
failed operator is ``Any``, so that downstream evaluation does not
cascade further errors. (There is some
discussion of potential alternatives :ref:`below <pep827-strict-kinds>`.)

Note that in some of these bounds below we write things like
Expand Down Expand Up @@ -622,10 +624,13 @@ Basic operators
'''''''''''''''

* ``GetArg[T, Base, Idx: Literal[int]]``: returns the type argument
number ``Idx`` to ``T`` when interpreted as ``Base``, or ``Never``
if it cannot be. (That is, if we have ``class A(B[C]): ...``, then
number ``Idx`` to ``T`` when interpreted as ``Base``, or generates a type
error if it cannot be or if the index is invalid.
(That is, if we have ``class A(B[C]): ...``, then
``GetArg[A, B, Literal[0]] == C``
while ``GetArg[A, A, Literal[0]] == Never``).
while ``GetArg[A, A, Literal[0]]`` is a type error).

If ``T`` is ``Any``, the result is ``Any``.

Negative indexes work in the usual way.

Expand All @@ -640,15 +645,19 @@ Basic operators
``Param`` types.

* ``GetArgs[T, Base]``: returns a tuple containing all of the type
arguments of ``T`` when interpreted as ``Base``, or ``Never`` if it
arguments of ``T`` when interpreted as ``Base``, or an error if it
cannot be.

If ``T`` is ``Any``, the result is ``Any``.

* ``Length[T: tuple]`` - Gets the length of a tuple as an int literal
(or ``Literal[None]`` if it is unbounded)

* ``Slice[S: tuple, Start: Literal[int | None], End: Literal[int | None]]``:
Slices a tuple type.

If ``S`` is ``Any``, the result is ``Any``.

* ``GetSpecialAttr[T, Attr: Literal[str]]``: Extracts the value
of the special attribute named ``Attr`` from the class ``T``. Valid
attributes are ``__name__``, ``__module__``, and ``__qualname__``.
Expand Down Expand Up @@ -688,11 +697,15 @@ Object inspection
methods).

* ``GetMember[T, S: Literal[str]]``: Produces a ``Member`` type for the
member named ``S`` from the class ``T``, or ``Never`` if it does not exist.
member named ``S`` from the class ``T``, or an error if it does not exist.

If ``T`` is ``Any``, the result is ``Any``.

* ``GetMemberType[T, S: Literal[str]]``: Extract the type of the
member named ``S`` from the class ``T``, or ``Never`` if it does not exist.

If ``T`` is ``Any``, the result is ``Any``.

* ``Member[N: Literal[str], T, Q: MemberQuals, Init, D]``: ``Member``,
is a simple type, not an operator, that is used to describe members
of classes. Its type parameters encode the information about each
Expand Down Expand Up @@ -1784,18 +1797,30 @@ This proposal is less "strictly-typed" than TypeScript

TypeScript has better typechecking at the alias definition site:
For ``P[K]``, ``K`` needs to have ``keyof P``. The ``extends``
conditional type operator narrows the type to help spuport this.
conditional type operator narrows the type to help support this.

It's not possible to define a type alias in TypeScript that fails at
expansion time, but it *is* possible to do so in this system.

We could do potentially better but it would require quite a bit more
machinery.
We could potentially also make this impossible but it would require
quite a bit more machinery.

* ``KeyOf[T]`` - literal keys of ``T``
* ``Member[T]``, when statically checking a type alias, could be
treated as having some type like ``tuple[Member[KeyOf[T], object,
str, ..., ...], ...]``
* ``GetMemberType[T, S: KeyOf[T]]`` - but this isn't supported yet.
TypeScript supports it.
* We would also need to do context sensitive type bound inference
* ``GetMemberType[T, S: KeyOf[T]]`` - Make ``GetMember`` have a bound
requiring the index be a key... but this kind of dependent bound
isn't supported currently. (TypeScript supports it.)
* We would also need to do context sensitive type bound
inference. This is subtle but obviously this sort of thing is done
at term level.

We think that this isn't worth the complexity, and is also not even
obviously better. TypeScript commonly requires doing many conditionals where
often it is always intended that they take the true branch--typically
the false branch returns ``never``, and these can be quite difficult
to track down.


Potential Future Extensions
Expand Down Expand Up @@ -1886,8 +1911,6 @@ simulated in other ways.
Open Issues
===========

* What invalid operations should be errors and what should return ``Never``?

* :ref:`Unpack of typevars for **kwargs <pep827-unpack-kwargs>`: Should
whether we try to infer literal types for extra arguments be
configurable in the ``TypedDict`` serving as the bound somehow? If
Expand Down
Loading