
Hi, I'd like to write a PEP for a new typing construct: NotType which, would be equivalent to any type but x. There has been an issue open on the typing repo for quite some time about this (https://github.com/python/typing/issues/801). After the recent-ish proposal for an IntersectionType, this would be a nice-to-have feature as it would complete the set theory operations for typed Python. I'd also like to propose implementing type.__invert__ to make this work, so it has built-in syntax like intersection and union as this is the closest thing to a not operator. Usecases: Something that takes any non-empty string ```py def fn(x: str & ~Literal[""]): ... ``` This also has nice integration with PEP 675 where the type of a Literal str is important. If you’d want to call this from any str you’d need a type guard. ```py def guard(x: str) -> TypeGuard[str & ~Literal[“”]]: return isinstance(x, str) and x != “” # or maybe bool(x) although this is probably much harder to implement ``` Something that takes any value but None ```py def fn(x: ~Literal[None]): ... ``` Something that requires not an integer ```py def not_an_int(x: Any) -> TypeGuard[~int]: ... ``` This also allows for narrowing in the negative case which is another requested feature (https://github.com/python/typing/issues/926) ```py @overload def is_none(value: None) -> Literal[True]: ... @overload def is_none(value: ~Literal[None]) -> Literal[False]: ... def is_none(value: Any) -> bool: return value is None def func(value: Optional[str]): if is_none(value): reveal_type(value) # None else: reveal_type(value) # str ``` Currently this isn’t the case ```py def is_none(value: Any) -> TypeGuard[None]: return value is None def func(value: Optional[str]): if is_none(value): reveal_type(value) # None else: reveal_type(value) # str | None ``` Overloading operators more correctly, more easily ```py @overload def __eq__(self, other: ~Self) -> Literal[False]: ... @overload def __eq__(self, other: Self) -> bool: ... def __eq__(self, other: object) -> bool: return isinstance(other, self.__class__) and ... ``` Something fun ```py reveal_type(~~str) # str ``` A few questions: Can you see any issues here? Do you have ideas for use cases I haven't thought of? Does anybody want to be a co-author on this?