TypeScript构造函数中数组方法赋值readonly属性报错原因及解决
问题原因与解决方案
为什么会出现这个错误?
TypeScript对readonly属性的赋值校验逻辑很保守:它只认可构造函数直接作用域内的赋值操作。而forEach这类数组方法的回调函数属于独立的函数作用域,TS的类型系统无法百分百确定这个回调会在构造函数执行期间同步运行(哪怕实际运行时是同步的),所以会把回调里的赋值判定为构造函数外的非法操作,触发"无法给只读属性赋值"的错误。
哪怕你在回调里直接写this.alpha = settings.alpha也不行——因为回调的作用域已经脱离了TS认定的构造函数安全赋值范围。
而构造函数里直接赋值、或者用构造函数内定义的常量键(比如const key = 'alpha')赋值能通过,是因为这些操作都在构造函数的直接作用域内,TS能明确识别这是合法的初始化操作。
保留数组方法的前提下怎么解决?
有几种可行的方案:
1. 用类型断言将this转为可写版本
定义一个工具类型移除readonly修饰符,然后在回调里把this断言成这个类型:
// 定义工具类型:移除对象所有属性的readonly修饰符 type Writable<T> = { -readonly [P in keyof T]: T[P] }; class MyClass { readonly alpha: number; constructor(settings: { alpha: number }) { (Object.keys(settings) as Array<keyof typeof settings>).forEach((key) => { // 断言后即可合法赋值 (this as Writable<MyClass>)[key] = settings[key]; }); } }
这个方法直接有效,而且能精准控制可写范围,不会影响其他地方的readonly校验。
2. 提前把this存为可写变量
在构造函数里先把this存成一个可写的变量,然后在回调里用这个变量操作:
class MyClass { readonly alpha: number; constructor(settings: { alpha: number }) { // 将this转为可写版本后存为变量 const self = this as Writable<MyClass>; (Object.keys(settings) as Array<keyof typeof settings>).forEach((key) => { self[key] = settings[key]; }); } }
这种方式代码可读性更高,避免在回调里重复写断言。
3. 用Object.assign简化操作(如果适合你的场景)
如果只是批量把settings的属性赋值给类实例,其实可以不用forEach,直接用Object.assign——TS允许在构造函数内用它给readonly属性赋值:
class MyClass { readonly alpha: number; constructor(settings: { alpha: number }) { Object.assign(this, settings); } }
这个方法最简洁,但如果你的逻辑必须用数组方法(比如要对每个键做额外处理),还是用前两种方案。
内容的提问来源于stack exchange,提问作者craigpatik
相关产品推荐
相关产品推荐

