[ty] Apply class decorators via try_call() (#22375)
## Summary Decorators are now called with the class as an argument, and the return type becomes the class's type. This mirrors how function decorators already work. Closes https://github.com/astral-sh/ty/issues/2313.
This commit is contained in:
@@ -234,3 +234,38 @@ def takes_no_argument() -> str:
|
||||
@takes_no_argument
|
||||
def g(x): ...
|
||||
```
|
||||
|
||||
## Class decorators
|
||||
|
||||
Class decorator calls are validated, emitting diagnostics for invalid arguments:
|
||||
|
||||
```py
|
||||
def takes_int(x: int) -> int:
|
||||
return x
|
||||
|
||||
# error: [invalid-argument-type]
|
||||
@takes_int
|
||||
class Foo: ...
|
||||
```
|
||||
|
||||
Using `None` as a decorator is an error:
|
||||
|
||||
```py
|
||||
# error: [call-non-callable]
|
||||
@None
|
||||
class Bar: ...
|
||||
```
|
||||
|
||||
A decorator can enforce type constraints on the class being decorated:
|
||||
|
||||
```py
|
||||
def decorator(cls: type[int]) -> type[int]:
|
||||
return cls
|
||||
|
||||
# error: [invalid-argument-type]
|
||||
@decorator
|
||||
class Baz: ...
|
||||
|
||||
# TODO: the revealed type should ideally be `type[int]` (the decorator's return type)
|
||||
reveal_type(Baz) # revealed: <class 'Baz'>
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user