Skip to content

Instantly share code, notes, and snippets.

@hjJunior
Last active December 8, 2023 02:12
Show Gist options
  • Save hjJunior/a7ab4fa27cd20f8f7d891d71c868a2ab to your computer and use it in GitHub Desktop.
Save hjJunior/a7ab4fa27cd20f8f7d891d71c868a2ab to your computer and use it in GitHub Desktop.
Typescript decorator
type DecorateClass<T extends {}, D extends Decorator<T>> = new (object: T) => D;
type DecoratedObject<T extends {}, D extends Decorator<T>> = T & D;
const decoratorHasProp = (decorator: Decorator, prop: string | symbol): prop is keyof typeof decorator => {
return Object.getPrototypeOf(decorator).hasOwnProperty(prop);
};
abstract class Decorator<T extends {} = {}> {
constructor(protected object: T) {}
static decorateObject<T extends {}, D extends Decorator<T>>(
object: T,
DecorateClass: DecorateClass<T, D>,
): DecoratedObject<T, D> {
const decorator = new DecorateClass(object);
const proxy = new Proxy(object, {
get(target: T, prop: string | symbol, receiver: any) {
if (decoratorHasProp(decorator, prop)) {
return decorator[prop];
}
return Reflect.get(target, prop, receiver);
},
});
return proxy as T & D;
}
}
type UserData = {
firstName: string;
lastName: string;
}
class UserDecorator<T extends UserData = UserData> extends Decorator<T> {
get fullName(): string {
return `${this.object.firstName} ${this.object.lastName}`;
}
}
const user: UserData = {
firstName: "Helio",
lastName: "Junior",
};
const decorated = Decorator.decorateObject(user, UserDecorator);
console.log(decorated.fullName);
@hjJunior
Copy link
Author

hjJunior commented Dec 8, 2023

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment