You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写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的类型剔除和状态区分,精准控制不同阶段的可用方法:

  1. 定义初始状态类型:仅包含编码方法(toAscii、toBase64),不暴露finish和result
  2. 定义已编码状态类型:仅保留finish方法,移除已调用过的编码方法,同时隐藏result
  3. 调整类的实现逻辑,让编码方法调用后返回对应的已编码状态类型

修改后的完整代码:

// 初始状态:仅能调用编码方法
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 05:13:16