二等兵打字稿?

是否有一种方法可以在 TypeScript 中为属性设置私有 setter?

class Test
{
private _prop: string;
public get prop() : string
{
return this._prop;
}


private set prop(val: string)
{
//can put breakpoints here
this._prop = val;
}
}

编译器抱怨 getter 和 setter 的可见性不匹配。我知道我可以只设置备份字段,但是在设置了值之后我就不能设置断点了。

我想过使用一个接口来隐藏 setter,但是接口只能定义一个属性,而不能决定它是否在 setter 上有一个 getter。

我错过了什么吗?似乎没有任何理由不允许私有 setter,生成的 JS 无论如何都不强制可见性,而且似乎比当前的替代方案更好。

我是不是漏掉了什么? 如果没有,就没有一个好的理由没有私人设置?

50491 次浏览

The TypeScript specification (8.4.3) says...

Accessors for the same member name must specify the same accessibility

So you have to choose a suitable alternative. Here are two options for you:

You can just not have a setter, which means only the Test class is able to set the property. You can place a breakpoint on the line this._prop =....

class Test
{
private _prop: string;
public get prop() : string
{
return this._prop;
}


doSomething() {
this._prop = 'I can set it!';
}
}


var test = new Test();


test._prop = 'I cannot!';

Probably the ideal way to ensure private access results in something akin to a "notify property changed" pattern can be implemented is to have a pair of private get/set property accessors, and a separate public get property accessor.

You still need to be cautious about someone later adding a direct call to the backing field. You could get creative in that area to try and make it less likely.

class Test
{
private _nameBackingField: string;


private get _name() : string
{
return this._nameBackingField;
}


private set _name(val: string)
{
this._nameBackingField = val;
// other actions... notify the property has changed etc
}


public get name(): string {
return this._name;
}


doSomething() {
this._name += 'Additional Stuff';
}
}

I also hope we could have public getter and private setter. Until we do, another way to handle this is to add additional private getter and setter:

class Test {
_prop: string;
public get prop(): string {
return this._prop;
}


private get internalProp(): string {
return this.prop;
}


private set internalProp(value: string) {
this._prop = value;
}


private addToProp(valueToAdd: string): void {
this.internalProp += valueToAdd;
}
}

Overview

The answers provided here are a bit outdated, although great for TypeScript version 4.2 and below. Per TypeScript's updated documentation, this is now possible as of TypeScript 4.3:

Since TypeScript 4.3, it is possible to have accessors with different types for getting and setting.

Here's a link to actual pull request and a snippet below showing this new feature.


Code

Below, the something accessors have differing visibility (public get and private set).

See this working in TypeScript Playground.

class A {
#somethingPrivate: number = 0;


public get something(): number {
return this.#somethingPrivate;
}


private set something(newValue: number) {
this.#somethingPrivate = Math.max(0, newValue);
}


public decrease(): A {
this.something--;
return this;
}


public increase(): A {
this.something++;
return this;
}
}


const a = new A();
a.increase();
console.log(a.something); // 1


a.decrease().decrease().decrease();
console.log(a.something); // 0

Note: If you're wondering what the #member does, it makes it truly private at runtime. See documentation here and great answers on this SO question.