https://github.com/alexfigliolia/decorators
A collection of useful decorators for every day programming
https://github.com/alexfigliolia/decorators
decorators
Last synced: about 2 months ago
JSON representation
A collection of useful decorators for every day programming
- Host: GitHub
- URL: https://github.com/alexfigliolia/decorators
- Owner: alexfigliolia
- Created: 2024-08-12T20:41:19.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2024-08-13T16:57:47.000Z (9 months ago)
- Last Synced: 2025-03-27T13:40:12.118Z (about 2 months ago)
- Topics: decorators
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/@figliolia/decorators
- Size: 64.5 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Decorators
Decorators for everyday programming.In this library you'll find a collection of useful shorthands for boosting productivity through the stage 3 Decorators API.
## Installation
```
npm i @figliolia/decorators
# or
yarn add @figliolia/decorators
```## API
1. [Bound](#bound)
2. [Cache](#cache)
3. [Debounce](#debounce)
4. [Throttle](#throttle)
5. [Animation Frame](#animation-frame)
6. [Log Browser](#log-browser)
7. [Log Server](#log-server)
8. [Measure Browser](#measure-browser)
9. [Measure Server](#measure-server)
10. [Unsafe Chainable](#unsafe-chainable)### Bound
Implicitely bind class methods to their instances
```typescript
import { bound } from "@figliolia/decorators";class MyClass {
private someField = "value";@bound
public someMethod() {
return this.someField;
}
}const { someMethod } = new MyClass();
// Works
someMethod();
```### Cache
Cache previous calls to a given method
```typescript
import { cache } from "@figliolia/decorators";class MyClass {
@cache
public expensive(x: number, y: number) {
// Compute expensive value
}
}const instance = new MyClass();
// computes on first execution
instance.expensive(1, 2);
// reads from cache then onwards as long as arguments match
instance.expensive(1, 2);
```### Debounce
Debounces calls to a given method for a pre-determined duration
```typescript
import { debounce } from "@figliolia/decorators";class MyClass {
@debounce(300)
public getData(query: string) {
void fetch(`/api/data?query=${query}`);
}
}const instance = new MyClass();
// Invokes 300ms following the last call
void instance.getData("searching for something");
```### Throttle
Throttles calls to a given method for a pre-determined duration
```typescript
import { throttle } from "@figliolia/decorators";class MyClass {
@throttle(300)
public getData(query: string) {
void fetch(`/api/data?query=${query}`);
}
}const instance = new MyClass();
// Invokes immediately, then disables later calls for 300ms
void instance.getData("searching for something");
```### Animation Frame
Invokes the target method using calls to `requestAnimationFrame`
```typescript
import { animationFrame } from "@figliolia/decorators";class MyClass {
node: HTMLElement;
constructor(ID: string) {
this.node = document.getElementById(ID);
}@animationFrame
public animate() {
const { translate } = this.node.style;
const current = parseInt(translate.slice(0, -2));
if(current === 100) {
return;
}
this.node.style.translate = `${current + 1}px`;
this.animate()
}
}const instance = new MyClass("elementID");
// animates an element's translateX property
instance.animate();
```### Log Browser
Logs invokation arguments and return values for a given method as long as the `NODE_ENV` is not `production`This method will use native colorized logging (in chrome and firefox)
```typescript
import { logBrowser } from "@figliolia/decorators";class MyClass {
@logBrowser
public async getData(query: string) {
return fetch(`/api/data?query=${query}`);
}
}const instance = new MyClass();
void instance.getData("searching for something");
```### Log Server
Logs invokation arguments and return values for a given method as long as the `NODE_ENV` is not `production`This method will use [Chalk]("https://www.npmjs.com/package/chalk") for colorized logging
```typescript
import { logServer } from "@figliolia/decorators";class MyClass {
@logServer
public async getData(query: string) {
return fetch(`/api/data?query=${query}`);
}
}const instance = new MyClass();
void instance.getData("searching for something");
```### Measure Browser
Logs the duration occupied by the target method at runtime
```typescript
import { measureBrowser } from "@figliolia/decorators";class MyClass {
@measureBrowser
public expensive() {
for(let i = 0; i < 1_000_000; i++) {}
}
}const instance = new MyClass();
instance.expensive();
```### Measure Server
Logs the duration occupied by the target method at runtime
```typescript
import { measureServer } from "@figliolia/decorators";class MyClass {
@measureServer
public expensive() {
for(let i = 0; i < 1_000_000; i++) {}
}
}const instance = new MyClass();
instance.expensive();
```### Unsafe Chainable
Overrides the return type of a given method, replacing it with the class instance
```typescript
import { chainable } from "@figliolia/decorators";class MyClass {
@chainable
public async method1() {
}
@chainable
public async method2() {
}
}const instance = new MyClass().method1().method(2);
// instance = MyClass
```## Stage 3 Decorator Proposal Vs. Experimental Decorators
If you're a typescript developer, the Experimental decorators API (found under the `experimentalDecorators` flag) has likely become familiar to you in recent years. While it's not far from the JavaScript [Stage 3 Proposal](https://github.com/tc39/proposal-decorators), there are significant syntactical mismatches between each decorators implementation that make interoperability impossible.Therefore, this library will not use TypeScript's experimental implementation, and instead favor JavaScript's Stage 3 Proposal. To read more on the Stage 3 proposal and where it varies from experimental decorators, I'd recommend [this article](https://2ality.com/2022/10/javascript-decorators.html).
### Limitations
Typescipt is limited in it's ability to transform types based on the presence of a decorator. This means, that if you modify argments or a return type in a decorator, Typescript will not know about it (yet). For the time-being (if you're a typescript user), I'd recommend not mutating method or property declarations in your decorators, and instead limit your usage functional transforms that maintain your application's type safety.### For JavaScript Users
Using this library without a syntax transform will not work any browser or node.js at the time of writing (August 12th, 2024). To ensure your code works smoothly across varying runtimes, check out the [Babel's Transform](https://babeljs.io/blog/2022/09/05/7.19.0#stage-3-decorators-14836) for Stage 3 Decorators.