6

我需要使用类属性名称的一些子集作为映射中的值,以便在类内部使用。在以下示例中,我已将 map 替换为数组。问题是如果属性被标记private,它不会在列表中keyof列出。如果需要包含私有名称,如何指定密钥类型?

var keys: Array<keyof A> = ["x", "y"]; // Error

class A {
  private x = 7;
  public y = 8;

  private keys: Array<keyof A> = ["x", "y"]; // Error
}

类外的变量和类内的私有属性都存在相同的错误:

类型“x”不能分配给类型“y”。

4

1 回答 1

3

正如您所注意到的,类privateprotected属性C不会作为keyof C. 这通常是可取的行为,因为大多数尝试对具有私有/受保护属性的类进行索引都会导致编译错误。有一个建议允许将类型映射到私有/受保护属性为公共的版本,这将为您提供一种方法来执行此操作……但是从 TypeScript 3.5 开始,此功能尚未实现。

所以这不起作用:

namespace Privates {
  export class A {
    private x: string = "a";
    public y: number = 1;
    private keys: Array<keyof A> = ["x", "y"]; // Error
  }
  var keys: Array<keyof A> = ["x", "y"]; // Error
}
const privateA = new Privates.A();
privateA.y; // number
privateA.x; // error: it's private
privateA.keys; // error: it's private

但也许您实际上并不需要这些属性private,因为对于该类的外部用户来说是不可见的。您可以使用模块/命名空间仅导出您想要的类的方面,如下所示:

namespace NotExported {
  class _A {
    x: string = "a";
    y: number = 1;
    keys: Array<keyof _A> = ["x", "y"]; // okay
  }
  export interface A extends Omit<_A, "x" | "keys"> {}
  export const A: new () => A = _A;
  var keys: Array<keyof _A> = ["x", "y"]; // okay
}

const notExportedA = new NotExported.A();
notExportedA.y; // number
notExportedA.x; // error: property does not exist
notExportedA.keys; // error: property does not exist

NotExported中,类构造函数_A和对应的类型_A不直接导出。在内部,keyof _A包含"x""y"键。我们导出的是一个构造函数和A一个相应的类型A,它省略了. 所以你得到了你想要的内部行为,而外部行为类似于。它们不是由于违规而无法访问,而是因为它们不是导出类型的一部分而无法访问。xkeys_ANotExported.APrivates.AxkeysprivateA

我实际上更喜欢后一种不导出实现细节的方法,而不是暴露属性的存在private,因为private属性实际上对如何使用相应的类有很大的影响。也就是说,private是关于访问控制,而不是关于封装。

好的,希望有帮助;祝你好运!

链接到代码

于 2019-07-17T14:32:56.580 回答