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?
