Typescript: Klass med egenskap genom namn getter/setter


Anta att det finns ett gränssnitt:

interface ServiceDataIf {
  somethingToDo(): void;
  mayBeAdd(arg: any): void;
  mayBeGet(name: string): any;
  readonly someVal: string;
  anotherVal: string;
  [name: string]: any;
}

Hur man implementerar detta gränssnitt i en klass:

class ServiceDataImpl1 implements ServiceDataIf {
  // easy with properties
  get someVal(): string {
    const result = /* somehow get it */;
    return result;
  }

  constructor() {}

  set anotherVal(v: string): void {
    // remember somewhere v
  }

  // plain methods easy as well
  somethingToDo(): void { /* do something */ }
  mayBeAdd(arg: any): void { /* do another something */ }
  mayBeGet(name: string): any {
    const result = /* somehow get it */;
    return result;
  }

  // How to implement this? [name: string]: any;
}

Metoder och egenskaper är okej, finns det något sätt att implementera by key-åtkomstmetoden med en klass? För att förtydliga, kan den där [name: string]: any-åtkomstmetoden implementeras som en klassmetod precis som get/set för egenskaper?

Så att det kan användas på det här sättet:

const myImpl = new ServiceDataImpl1();

// read
const val1 = myImpl['something'];
// write
myImpl['something'] = 256;

Svar #1

Slutligen, som nyckelord att söka efter, kallas ett sådant gränssnitt indexer. Då finns tillräcklig information tillgänglig. Till exempel, enligt följande diskussioner, verkar det vara omöjligt att implementera ett sådant gränssnitt direkt i Typescript:

  • Kan jag skapa en klass []-operator i Typescript
  • Implementera en indexerare i en klass i TypeScript

Eftersom det orsakar tvetydighet med JavaScript, så att det är förbjudet.

Men det finns Proxy i ES2015 som tillåter att implementera önskad funktionalitet, även om det inte är särskilt enkelt. Följande illustrerar sättet, men inte en fullständig implementation.

interface SomeIf {
  [name: string]: any;
}

class SomeImpl implements SomeIf {
  constructor() {
    return new Proxy(this, {
      get: (obj: any, key: string | number | symbol, receiver: any) => {
        console.log('get', key, obj, receiver);
        return key === 'abc' ? 53 : key in obj ? obj[key] : undefined;
      },
      set: (obj: any, key: string | number | symbol, value: any, receiver: any) => {
        console.log('set', key, value, obj, receiver);
        return true;
      }
    });
  }
}

const impl1 = new SomeImpl();
impl1['abc'] = 123;
console.log(`impl1['abc']`, impl1['abc']);

Det bör noteras att äldre webbläsare inte kommer att stödja Proxy, om det önskas för användning i webbläsare.

Svar #2

Om jag förstår korrekt nu, vill du att egenskaper ska läggas till dynamiskt i klassen. Och sedan vill du kasta ett kompilationsfel om du försöker komma åt något som inte lades till eller inte finns i gränssnittet.

Den här raden

[name: string]: any;

Tillåter i princip ATT VILKEN egenskap som helst av VILKEN typ som helst att existera.

TypeScript kan inte sluta typer vid körning. Så, som definierat i gränssnittet, tillåter det att vilken egenskap som helst kan existera. Även om den inte lades till någonstans.

TypeScript kan bara göra kompileringstidkontroller.

Ah. Och du kan inte tvinga getters/setters i gränssnittet. Som beskrivet här: Är det möjligt att använda getters/setters i gränssnittsdefinitionen?

Relaterade artiklar