javascript - Skapa en klass med getters baserat på egenskaperna hos en annan klass


Säg att jag har en klass A med hundra egenskaper:

class A {
  FOO = "foo";
  BAR = "bar";
  // (...) 98 more properties
}

I TypeScript, hur går man tillväga för att dynamiskt definiera en klass B med en getter för varje egenskap i klass A?
Den motsvarande statiskt definierade klassen B skulle se ut så här:

class B {
  get FOO() {
    someFunction('FOO');
  }

  get BAR() {
    someFunction('BAR');
  }

  // (...) 98 more getters
}

Relationen mellan dessa klasser är som följer:

  • ett getter-namn i B är lika med egenskapsnamnet i A
  • kroppen av getter i B är exakt anropet av funktionen someFunction med ett enda argument som är en sträng med namnet på gettern

Svar #1

Ett alternativ är att definiera getters på språng:

class A {
    FOO = "foo";
    BAR = "bar";
    // (...) 98 more properties
}

function someFunction(p) {
    console.log('someFunction', p)
}

class B {
    constructor(a) {
        for (let p of Object.getOwnPropertyNames(a))
            Object.defineProperty(this, p, {
                get: () => someFunction(p) 
            })
    }
}

b = new B(new A)
b.FOO
b.BAR

Jag antar att du behöver skicka a till someFunc också, annars hur skulle det veta från vilket objekt det ska hämta egenskapen?

En annan är att använda en Proxy:

class A {
    FOO = "foo";
    BAR = "bar";
    // (...) 98 more properties
}

function someFunction(p) {
    console.log('someFunction', p)
}

class B {
    constructor() {
        return new Proxy({}, {
            get(target, p) {
                return p in target ? Reflect.get(target, p) : someFunction(p)
            }
        })
    }
}

b = new B()
b.FOO
b.BAR

I det senare fallet är B och A faktiskt oberoende, så att B bara är ett "hål"-objekt som omdirigerar allt till someFunc.

Svar #2

Detta är @georgs svar, andra förslaget, något ändrat för att faktiskt fungera för mig:

class A {
    FOO = "foo";
    BAR = "bar";
    // (...) 98 more properties
}

function someFunction(p, moreStuff) {
    console.log('someFunction', p, moreStuff)
}

class B extends A {
    constructor(private something: Something) {
        super();
        const someth = this.something;
        return new Proxy({} as any, {
            get(target, p) {
                return p in target ? Reflect.get(target, p) : someFunction(p, someth)
            }
        })
    }
}

b = new B()
b.FOO
b.BAR