Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to allow a class decorator to return anything #543

Closed
alamhubb opened this issue Sep 17, 2024 · 1 comment
Closed

Is it possible to allow a class decorator to return anything #543

alamhubb opened this issue Sep 17, 2024 · 1 comment

Comments

@alamhubb
Copy link

alamhubb commented Sep 17, 2024

Why must class decorators have a return value of T / void / undefined?

I need to implement such a function, not using decorators,Methods that return class instance objects

function ReturnObj(Constructor: Function) {
    return new Constructor()
}

class Test {
    name: string = 'name'
}


export default ReturnObj(Test)

This is too cumbersome to write, I want to use a decorator to implement it

function ReturnObj(Constructor: Function) {
    return new Constructor()
}

@ReturnObj
export default class Test {
    name: string = 'name'
}

Then I got an error, I looked up the relevant rules and found, microsoft/TypeScript#50820

image

Because I am a newbie to typescript, I can't think of the necessary reason for this design. I am curious about the original intention of this rule. Can you tell me?

In stage 2, any content is allowed to be returned, but it is not allowed in stage 3.

If it is still allowed, what problems will there be?

@alamhubb alamhubb changed the title Can class decorators be allowed to return anything? Is it possible to allow a class decorator to return anything Sep 17, 2024
@pzuraq
Copy link
Collaborator

pzuraq commented Sep 18, 2024

So the only real rule in the spec for the return value of a class decorator is that it must be constructable, e.g. you must be able to do new ReturnValue() to it. That does make what you want with just creating an instance tricky, but it would be doable with a Proxy for instance (since you can implement the constructor trap.)

The logic behind this is that decorators should not fundamentally change the "shape" of the value they are decorating. So, if a decorator is applied to a function, the result should be a function. If applied to a class, the result should be a class/new-able value. The reasoning is that if you were to come into a project with no outside knowledge at all, whatsoever, would you be able to have some idea of the constraints of what this decoration is doing?

Consider:

@foo
class Foo {
  @bar
  baz = 123;
}

If you do not know the definitions of @foo or @bar, what can you say about Foo? Currently, you can know the following:

// valid
const instance = new Foo();

// valid
instance.bar();

If we remove the restrictions, then you really can't say anything. Most of the time it would be valid, but sometimes it wouldn't. If you tried to do new Foo() and it didn't work, you might have to dig into a bunch of library code to figure out why. That breaks some amount of encapsulation.

There were also performance issues with allowing any return value, because the engine could no longer make assumptions about what the value would be, but I think those are secondary issues compared to the mental model and clarity that decorators have with these restrictions.

@alamhubb alamhubb closed this as completed Oct 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants