为什么TypeScript中interface定义的readonly属性没有生效?
问题核心原因
你遇到的现象是TypeScript的正常设计,并未违反readonly的约束规则,核心原因有两点:
- 类实现接口时,接口的readonly修饰符不会自动同步到实现类的属性上
- 实例变量的类型声明用了无readonly约束的实现类
Book,而非带约束的接口ReadExample
详细解释
接口readonly的作用范围
接口的readonly仅约束该接口类型本身的属性读写规则,本质是约定“使用该接口类型访问属性时,该属性只能读不能写”,并不会强制要求实现它的类也把对应属性设为readonly。
可写属性天然满足“可读”的契约要求,因此类实现接口时,完全可以把接口标记为readonly的属性定义为可写属性,这是符合TS类型规则的。你当前代码中Book类的book_id就是普通可写属性,因此操作Book类型的实例时,TS允许修改该属性。变量类型声明的影响
你当前的实例声明代码是let book: Book = new Book(2, 'Sis'),TS会按照Book类的类型定义做检查,而Book类的book_id没有readonly修饰,自然不会报错。
如果你把变量类型指定为ReadExample:let book: ReadExample = new Book(2, 'Sis'),此时TS会按照ReadExample的规则做检查,再尝试修改book.book_id就会触发只读属性报错。
修复方案
方案1:给实现类的对应属性加readonly修饰
如果要求所有Book类实例的book_id都不可修改,直接给类属性加readonly修饰即可:
interface ReadExample { readonly book_id: number, book_name: string } class Book implements ReadExample{ readonly book_id= 3; // 新增readonly修饰 book_name = 'A Thousand Stars'; constructor(book_id:number, book_name:string){ this.book_id = book_id; this.book_name = book_name; } } let book: Book = new Book(2, 'Sis'); book.book_id = 3; // 此处TS会抛出只读属性不可修改的报错
方案2:声明实例时指定类型为带readonly约束的接口
如果不需要限制所有Book类实例的book_id只读,只需要当前实例遵循ReadExample的约束,直接修改变量类型即可:
let book: ReadExample = new Book(2, 'Sis'); // 变量类型指定为ReadExample book.book_id = 3; // 此处TS会抛出只读属性不可修改的报错
内容的提问来源于stack exchange,提问作者Bidisha Das
相关产品推荐
相关产品推荐

