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

TypeScript实现调用后移除类方法的解决方案问询

实现调用后自动移除自身的类方法类型约束与运行时限制

问题描述

我需要实现一个类,要求类的方法被调用后,返回的实例类型中自动排除该方法,同时运行时也无法再次调用该方法。以包含step1、step2、step3的Setup类为例:

class Setup {
    step1() {
        return this;
    }
    
    step2() { 
        return this;
    }
    
    step3() { 
        return this;
    }
}

let setup = new Setup();

具体需求:

  • 调用step1后,返回的实例只能调用step2和step3;调用step2后只能调用step3,以此优化开发体验
  • 方法调用顺序不受限制,比如可以先调用step3再调用step1
  • 运行时一旦方法被调用,就无法再次调用,例如:
    setup
        .step1()
        .step2()
        .step1(); // 此处应报错,因为step1已经被调用过
    

我之前尝试用Omit类型实现,但每次都是基于原始Setup类型排除单个方法,导致调用step2后仍然能看到step1可选,没法实现累计排除已调用方法的效果:

export type Omit<A extends object, K extends string> = Pick<A, Exclude<keyof A, K>>

class Setup {
    step1(): Omit<Setup, 'step1'> {
        return this;
    }
    
    step2(): Omit<Setup, 'step2'>{ 
        return this;
    }
    
    step3():Omit<Setup, 'step3'>{ 
        return this;
    }
}

let setup = new Setup();

解决方案

要实现累计排除已调用方法的效果,需要结合TypeScript泛型跟踪已调用方法和运行时动态删除方法两部分:

完整实现代码

type SetupMethods = 'step1' | 'step2' | 'step3';

// 用泛型T跟踪已调用的方法,默认值为空集合
class Setup<T extends SetupMethods = never> {
    step1(): Omit<Setup<T | 'step1'>, T | 'step1'> {
        delete (this as any).step1;
        return this as Omit<Setup<T | 'step1'>, T | 'step1'>;
    }

    step2(): Omit<Setup<T | 'step2'>, T | 'step2'> {
        delete (this as any).step2;
        return this as Omit<Setup<T | 'step2'>, T | 'step2'>;
    }

    step3(): Omit<Setup<T | 'step3'>, T | 'step3'> {
        delete (this as any).step3;
        return this as Omit<Setup<T | 'step3'>, T | 'step3'>;
    }
}

// 测试示例
const setup = new Setup();
setup.step1().step2().step3(); // 正常链式调用
setup.step1().step3().step2(); // 正常链式调用
setup.step3().step1().step3(); // 类型报错:step3不存在,运行时也会报错
setup.step1().step2().step1(); // 类型报错:step1不存在,运行时也会报错

关键说明

  1. 泛型跟踪已调用方法:

    • 类的泛型参数T用来记录已经被调用过的方法名,初始值为never(表示没有方法被调用)
    • 每个方法返回的类型是Omit<Setup<T | 当前方法名>, T | 当前方法名>,这样每次调用方法后,返回的实例类型会自动排除所有已调用过的方法(包括当前方法)
  2. 运行时删除方法:

    • 在每个方法内部,通过delete this[方法名]删除实例上的该方法,确保运行时无法再次调用
    • 这里用(this as any)是因为TypeScript会阻止删除类的原型方法,通过类型断言绕过检查(实际运行时操作的是实例自身的属性,不会影响原型)
  3. 类型约束生效:

    • TypeScript会根据泛型参数的变化,动态推导返回实例的可用方法,比如调用step1后,返回的实例类型就不再包含step1,编辑器会自动提示可用方法,同时报错非法调用

内容的提问来源于stack exchange,提问作者Anirudh Modi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 12:17:46