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

Usage of decorators in raw functions #44828

Closed
4 of 5 tasks
thebergamo opened this issue Jun 30, 2021 · 4 comments
Closed
4 of 5 tasks

Usage of decorators in raw functions #44828

thebergamo opened this issue Jun 30, 2021 · 4 comments
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints

Comments

@thebergamo
Copy link

Suggestion

Decorators are a very useful feature when we have to encapsulate some behaviors and enhance our code with such.
But, a game changer for those decorators would be if we could use them in raw functions as well, not only in class based scenarios.

🔍 Search Terms

  • decorators

✅ Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

I would like to be able to decorate a raw/plain JS function with decorators. So I won't need to every time I need a decorator wrap my function inside a class to be able to use it.

📃 Motivating Example

Today, if you need to create a decorator, let's say to wrap a Lambda handler function, you would need to somehow wrap it into a class and initialize this class and expose the handler of it.
But, if you could have decorators directly in raw JS function it would be more smooth and less "boilerplate".

💻 Use Cases

For example:

export function handler(@Param('pathParamId') pathParamId: string) {}

But rather, in order to have something similar, you would need to have this code:

@Handler
class MyHandler implements LambdaHandler {
    handler(@Param('pathParamId') pathParamId: string) {}
}
@MartinJohns
Copy link
Contributor

Related: #7318

In the end this depends on TC39, so you should take a suggestion there. Please also note that the current decorator support in TypeScript is based on an old and outdated proposal. The team made clear that they don't do any more work on decorator support until the proposal is finished.

@andrewbranch andrewbranch added the Out of Scope This idea sits outside of the TypeScript language design constraints label Jun 30, 2021
@andrewbranch
Copy link
Member

  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)

is a non-negotiable checkbox, I’m afraid.

@thebergamo
Copy link
Author

I was afraid that I should mark all tue boxes. But I was pretty sure that such feature would fall in this category.

But it makes sense to at least wait for TC39 before having it in TS.

Pity, but understandable.

@andrewbranch You could close for comments as well to avoid people finding this issue and start another big thread.

Thanks for fast reply also @MartinJohns :)

@nik-kita
Copy link

nik-kita commented Sep 9, 2021

This is my solution:

this simple decorator wrap any function and log its execution time in console

execution-time.decorator.ts

export function ExecutionTime() {
  return (target: Object, key: string, descriptor: PropertyDescriptor) => {
    const { value: origin } = descriptor;
    descriptor.value = (...args: any[]) => {
      const label = 'target.constructor.name'+'.'+'key'+'(...)';
      console.time(label);
      const result = origin(...args);
      if (result instanceof Promise) {
        return result.finally(console.timeEnd.bind({}, label));
      }
      console.timeEnd(label);
      return result;
    };
  };
}

Because we can decorate only methods, i make target function as a static in some class and then import const that equals this static method

some-function.ts

import { ExecutionTime } from './execution-time.decorator';
class WrappedClass {
  @ExecutionTime()
  static async originSomeFunction() {
    console.log('done');
  }
}
export const someFunction = WrappedClass.originSomeFunction;

Final usage in client code:

index.ts

import { someFunction } from './some-function';
someFunction();

P. S.

Of course this is not a raw function. But its interface, i mean its usage looks like usage of raw function. And if you want wrap it with decorators, you should go to its wrapped class and in it do it with origin static method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints
Projects
None yet
Development

No branches or pull requests

4 participants