TL;DR:使用私有标识符来定义您的私有字段。这样,它们的可访问性也将在运行时强制执行。
正如已经指出的那样,可访问性仅由 TypeScript 转译器静态(在编译时)强制执行。
因此,所有属性,无论是公共的还是私有的,都作为普通的 JavaScript 属性发出。Proxy
这里没有魔法,除了使用 a来捕获ownKeys()
方法或使用Object.defineProperties
而不是使用 TypeScript 方式声明它们之外,您无法做任何事情来隐藏它们。对于后一种想法,我想出了一个例子:
class Foo {
constructor() {
Object.defineProperties(this, {
bar: {
enumerable: false,
value: "Hello world"
}
})
console.log((this as any).bar)
}
}
上面的示例可以在TypeScript Playground中进行测试。
但是,我认为这样做是一种反模式,因为它破坏了所有 TypeScript 的安全性,这是选择它而不是仅仅写出 JavaScript 代码的唯一原因。
因此,我们剩下的唯一解决方案是使用私有标识符。这是一个 TypeScript 功能,因此名称以开头的任何字段#
不仅在编译时,甚至在运行时都被强制为私有。
class Foo {
#bar = "Hello world"
constructor() {
console.log(this.#bar)
}
}
console.log(Object.keys(new Foo()))
上面的示例可以在TypeScript Playground中进行测试。
这是如何运作的?好吧,你可能只是看一下转译的 JavaScript 代码,你会突然注意到一个WeakMap
. 实际上,在WeakMap
定义其声明类的相同词法范围内,为具有私有标识符的类中的每个字段定义了对 new 的引用。无论在何处访问私有字段,都通过调用使用给定映射(在引用该字段时传递)的 getter 或 setter 函数来获取或设置给定键的值,这是访问该字段的类的实例在。还在 getter 和 setter 函数中进行运行时检查,以便TypeError
在使用未注册的接收者调用时抛出 a ,以防止私有字段被不同类型的实例或根本没有实例访问。