# Class definitions ## `__new__` return type Python's `__new__` method can return any type, not just an instance of the class. When `__new__` returns a type that is not assignable to the class instance type, we use that return type directly. ### `__new__` returning a different type ```py class ReturnsInt: def __new__(cls) -> int: return 42 reveal_type(ReturnsInt()) # revealed: int x: int = ReturnsInt() # OK y: ReturnsInt = ReturnsInt() # error: [invalid-assignment] ``` ### `__new__` returning a union type ```py class MaybeInt: def __new__(cls, value: str) -> "int | MaybeInt": try: return int(value) except ValueError: return object.__new__(cls) reveal_type(MaybeInt("42")) # revealed: int | MaybeInt a: int | MaybeInt = MaybeInt("42") # OK b: int = MaybeInt("42") # error: [invalid-assignment] ``` ### `__new__` returning the class type When `__new__` returns the class type (or `Self`), the normal instance type is used. ```py class Normal: def __new__(cls) -> "Normal": return object.__new__(cls) reveal_type(Normal()) # revealed: Normal ``` ### `__new__` with no return type annotation When `__new__` has no return type annotation, we fall back to the instance type. ```py class NoAnnotation: def __new__(cls): return object.__new__(cls) reveal_type(NoAnnotation()) # revealed: NoAnnotation ``` ## Deferred resolution of bases ### Only the stringified name is deferred If a class base contains a stringified name, only that name is deferred. Other names are resolved normally. ```toml [environment] python-version = "3.12" ``` ```py from ty_extensions import reveal_mro A = int class G[T]: ... class C(A, G["B"]): ... A = str B = bytes reveal_mro(C) # revealed: (, , , typing.Generic, ) ```