function add(a, b) {
console.log(`calling add, args:`, ...args);
const result = a + b;
console.log(`finished add, result:`, result);
return result;
}
function sub(a, b) {
console.log(`calling sub, args:`, ...args);
const result = a - b;
console.log(`finished sub, result:`, result);
return result;
}
function debugLog(fn) {
return (...args) => {
console.log(`calling ${fn.name}, args:`, ...args);
const result = fn(...args);
console.log(`finished ${fn.name}, result:`, result);
return result;
};
}
const add = debugLog((a, b) => a + b);
const sub = debugLog((a, b) => a - b);
const C = decorate1(
decorate2(
class {
// ...
}
)
);
class C {
// ???
method() {}
}
function dec(value, context) {
// apply decoration
}
function dec(value, context) {
// apply decoration
}
@dec
class C {
@dec m() {}
@dec get x() {}
@dec set x(v) {}
@dec y = 123;
@dec accessor z = 456;
}
function dec(value, context) {
// apply decoration
}
@dec
class C {
@dec m() {}
@dec get x() {}
@dec set x(v) {}
@dec y = 123;
@dec accessor z = 456;
}
@second
@first
class C {
@second @first x = 123;
}
function dec(Class) {
return class Decorated extends Class {
// ...
}
}
@dec class C {}
function logResult(method) {
return function (...args) {
const result = method.apply(this, args);
console.log(result);
return result;
}
}
class C {
@logResult m() {
return 123;
}
}
new C().m(); // logs "123"
function logResult(method) {
return function (...args) {
const result = method.apply(this, args);
console.log(result);
return result;
}
}
class C {
@logResult get x() {
return 123;
}
}
new C().x; // logs "123"
function add1() {
return function (value) {
return value + 1;
}
}
class C {
@add1 x = 1;
}
console.log(new C().x); // 2
class C {
accessor x = 123;
}
class C {
accessor x = 123;
}
// is approximately the same as
class C {
#x = 123;
get x() {
return this.#x;
}
set x(value) {
this.#x = value;
}
}
function addOneAndLog({ get, set }) {
return {
get() {
const value = get.call(this);
console.log('getting value:', value);
return value;
},
set(value) {
console.log('setting value:', value + 1)
set.call(this, value + 1);
},
init(value) {
return value + 1;
}
}
}
class C {
@addOneAndLog accessor x = 1;
}
const c = new C();
c.x; // getting value: 2;
c.x = 2; // setting value: 3;
interface DecoratorContext {
kind: 'class' | 'method' | 'getter' | 'setter' | 'field' | 'accessor';
name: string | symbol;
private?: boolean;
static?: boolean;
access: {
get?(): unknown;
set?(value: unknown): void;
};
addInitializer?(initializer: () => void): void;
}
function bound(_, { access, addInitializer }) {
addInitializer(function () {
// get the final method
const method = access.get.call(this);
// set it to a bound version
access.set.call(this, method.bind(this));
});
}
class C {
@bound m() {}
}
class C {
@inject('foo') bar;
}
function inject(name) {
return function injectionDecorator() {
// ...injection logic using name
}
}
class C {
@inject('foo') bar;
}
class C {
// valid
@foo.bar x;
@foo.bar() x;
@(foo['bar']().baz) x;
// invalid
@foo['bar'] x;
@foo().bar() x;
}
// before
@dec export class Foo {
}
// after
export @dec class Foo {
}
function makeAClass() {
return @dec class Bar {
// ...
}
}
// before
export class Foo {
@foo().bar() x;
}
// after
export @dec class Foo {
@(foo().bar()) x
}