Reputation: 2053
Suppose, there is an interface:
interface ServiceDataIf {
somethingToDo(): void;
mayBeAdd(arg: any): void;
mayBeGet(name: string): any;
readonly someVal: string;
anotherVal: string;
[name: string]: any;
}
How to implement this interface in a class:
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;
}
Methods and properties are ok, is there any way to implement by key
accessor with a class? To clarify, can that [name: string]: any
accessor be implemented as a class method just like get/set for properties?
So that it can be used like this:
const myImpl = new ServiceDataImpl1();
// read
const val1 = myImpl['something'];
// write
myImpl['something'] = 256;
Upvotes: 5
Views: 4717
Reputation: 2053
Finally, as keyword to search, such interface is called indexer
. Then enough information is available. For instance, as per following discussions, it seems to be impossible to implement such interface out of the box in Typescript:
Because it causes ambiguity with JavaScript, so that it is prohibited.
However, there is Proxy
in ES2015 which allows to implement desired functionality, although not very easy. Following illustrates the way, but not complete 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']);
It should be noted that, older browsers won't support Proxy
, if desired for use in browsers.
Upvotes: 2
Reputation: 2883
If I understand correctly now, you want properties to be dynamically added to the class. And then want to throw compilation error if you try to access something that was not added or is not in the interface.
This line
[name: string]: any;
Basically allows ANY property of ANY kind to exist.
TypeScript can not infer types in the runtime. So, as defined in the interface, it will allow any property to exist. Even if it was not added somewhere.
TypeScript can only make compile time checks.
Ah. And you can't enforce getters/setters in the interface. As described here: Is it possible to use getters/setters in interface definition?
Upvotes: 0