如何编写TypeScript类型声明,控制链式调用类的属性可见性?
问题:限制Encoder类的初始状态访问权限
我有一个支持链式调用的TypeScript类,代码如下:
interface EncoderResult { result: string | number finish(): string | number } interface Ascii extends EncoderResult { toAscii<T extends UniversalEncoder>( this: T, chars?: string ): Omit<T, 'toAscii'> } interface Base64 extends EncoderResult { toBase64<T>(this: T): Omit<T, 'toBase64'> } type UniversalEncoder = Ascii & Base64 class Encoder implements UniversalEncoder { result!: string | number toAscii<T extends Omit<UniversalEncoder, 'toAscii'>>( this: T, chars?: string ): Omit<T, 'toAscii'> { this.result = chars return this } toBase64<T>(this: T): Omit<T, 'toBase64'> { return this } finish() { return this.result } }
现在遇到的问题是:刚实例化的Encoder对象,就能直接调用finish()或者访问result属性,但这些操作在初始状态下没有实际意义。需要调整类型声明,实现以下约束效果:
const encoder = new Encoder() encoder.finish() // 错误:类型上不存在属性'finish' encoder.result // 错误:类型上不存在属性'result' encoder.toAscii().result // 错误:类型上不存在属性'result' encoder.toAscii().toAscii() // 不允许调用 encoder.toAscii().finish() // 预期可调用
解决方案
核心思路是拆分不同状态的类型,通过TypeScript的类型剔除和状态区分,精准控制不同阶段的可用方法:
- 定义初始状态类型:仅包含编码方法(
toAscii、toBase64),不暴露finish和result - 定义已编码状态类型:仅保留
finish方法,移除已调用过的编码方法,同时隐藏result - 调整类的实现逻辑,让编码方法调用后返回对应的已编码状态类型
修改后的完整代码:
// 初始状态:仅能调用编码方法 type InitialEncoder = { toAscii(chars?: string): EncodedState<Omit<InitialEncoder, 'toAscii'>> toBase64(): EncodedState<Omit<InitialEncoder, 'toBase64'>> } // 已编码状态:仅能调用finish,隐藏result和已使用的编码方法 type EncodedState<T> = T & { finish(): string | number } class Encoder implements InitialEncoder { // 将result设为私有,彻底禁止外部直接访问 private result!: string | number toAscii(chars?: string): EncodedState<Omit<InitialEncoder, 'toAscii'>> { this.result = chars ?? '' return this as EncodedState<Omit<InitialEncoder, 'toAscii'>> } toBase64(): EncodedState<Omit<InitialEncoder, 'toBase64'>> { // 可在此补充Base64编码逻辑,示例用占位值代替 this.result = 'base64-encoded' return this as EncodedState<Omit<InitialEncoder, 'toBase64'>> } finish() { return this.result } }
效果验证
- 初始状态:
new Encoder()仅能看到toAscii和toBase64方法,调用finish()或访问result会触发TypeScript错误 - 调用
toAscii()后:对象类型自动切换为已编码状态,仅能调用finish(),无法重复调用toAscii(),也不能直接访问result - 调用
finish()后:返回最终编码结果,符合预期逻辑
内容的提问来源于stack exchange,提问作者Loskau
相关产品推荐
相关产品推荐

