从构造函数调用的方法中给`readonly`属性赋值

19

我有一个简单的类,想在构造函数发起的一个方法中为只读属性赋值,但是它报错说:[ts] Cannot assign to 'readOnlyProperty' because it is a constant or a read-only property. 即使我从构造函数调用了process方法,为什么我也不能给该属性赋值呢?

示例代码:

class C {
    readonly readOnlyProperty: string;
    constructor(raw: string) {
        this.process(raw);
    }
    process(raw: string) {
        this.readOnlyProperty = raw; // [ts] Cannot assign to 'readOnlyProperty' because it is a constant or a read-only property.
    }
}

2
TypeScript编译器如何推断process()只会从构造函数中调用? - Robby Cornelissen
@RobbyCornelissen 在这种情况下表现出的确切问题是一个有效的关注点,但匿名回调内部的构造函数也会出现同样的问题,例如在使用数组方法时。 - Emile Bergeron
5个回答

12

我通常使用这个解决方法:

get myValue(): boolean { return this._myValue }
private _myValue = true

结果:

  • myValue – 从外部是只读
  • _myValue – 可以在类内部进行修改

这种解决方法的优点是,你的IDE可以重构你的属性。此外,我们没有滥用只读属性,这可以避免编译、优化或代码审查时出现的错误。如果不是今天,那么也很快就会。这就是为什么我不会使用类似以下的东西:

// hack, may cause problems (refactoring is not possible)
(this as any).readOnlyProperty = raw

// hack, may cause problems (we write a non-writable)
(this.readOnlyProperty as boolean) = raw

// hack, may cause problems (refactoring is not possible)
Object.assign(this, {readOnlyProperty: raw})

12

不要将this as any进行强制类型转换,而是应该通过修改这个属性来强制类型检查:

// OK
(this.readOnlyProperty as string) = raw; 

// TS2322: Type '5' is not assignable to type 'string'.
(this.readOnlyProperty as string) = 5;   

我认为这是最干净、最高效的答案。 - tru7
@tru7 我真的很好奇。如果你想设置属性,你必须重新定义它。这怎么可能是最干净、最有效的方法呢?特别是当你使用类时!我认为 chens 的方法有点 hacky。看看我的答案,已经有一个经典的方法来解决这个用例了。 - Jan

1
当您创建一个单独的函数来分配值时,这个单独的函数可以从除构造函数之外的其他地方使用。编译器不会检查(对于公共函数,甚至无法检查)该函数是否仅从构造函数调用。所以会出错。
您有两种方法来分配值。更清晰的方法是将单独函数的核心放入构造函数中。另一种方法是将“this”转换为“any”(这会使您失去类型检查,因此不建议使用,除非您确实知道自己在做什么)。
(this as any).readOnlyProperty = raw

0

只是尝试

Object.assign(this, {readOnlyProperty: raw})

1
虽然这样做可以消除TypeScript警告,就像问题中所要求的那样,但最好的答案不仅仅是代码。对于可能面临相同问题的其他读者来说,了解这个答案的工作方式以及为什么使用它而不是其他答案是有帮助的。 - anothermh

0

这是一个比较老的问题,但我认为分享一下我的解决方法还是有价值的。我倾向于从方法中返回你想要设置的值,这样你仍然可以分离逻辑,同时保持只读属性,而不需要任何可能违法的绕过方式。例如...

class C {
    readonly readOnlyProperty: string;
    constructor(raw: string) {
        this.readOnlyProperty = this.process(raw);
    }
    process(raw: string) {
         // ...some logic that processes 'raw'...

        return raw;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接