Typescript:具有按名称 getter / setter 属性的类

mur*_*adm 5 typescript

假设有一个接口:

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

如何在类中实现该接口:

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;
}
Run Code Online (Sandbox Code Playgroud)

方法和属性都可以,有没有办法用by key类来实现访问器?澄清一下,该[name: string]: any访问器是否可以像属性的 get/set 一样实现为类方法?

这样它就可以像这样使用:

const myImpl = new ServiceDataImpl1();

// read
const val1 = myImpl['something'];
// write
myImpl['something'] = 256;
Run Code Online (Sandbox Code Playgroud)

mur*_*adm 2

最后,作为搜索的关键字,这样的接口称为indexer。然后就可以获得足够的信息。例如,根据以下讨论,似乎不可能在 Typescript 中开箱即用地实现此类接口:

因为它会导致 JavaScript 的歧义,所以被禁止。

然而,ProxyES2015 中允许实现所需的功能,尽管不是很容易。下面说明了方法,但没有完整实现。

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']);
Run Code Online (Sandbox Code Playgroud)

应该注意的是,Proxy如果需要在浏览器中使用,旧版浏览器将不支持 。