TypeScript实现@End装饰器 强制链式调用末尾必须执行run方法
方案1:类型约束强制必须调用run(),漏写直接编译报错
TypeScript 本身的装饰器仅负责运行时逻辑,没有原生支持类似 Java @End 注解的静态校验能力,但可以通过拆分类型完全实现漏写 run() 就触发编译报错的效果:
// 仅包含链式调用方法的类型,不暴露run方法 interface UserActionChain { attemptsTo(tasks: (() => Promise<void>)[]): UserActionChain expects(expectations: (() => Promise<void>)[]): UserActionChain } // 可执行的子类型,新增run方法 interface RunnableUser extends UserActionChain { run(): Promise<void> } class User implements RunnableUser { public name: string; public works: (() => Promise<void>)[]; constructor(name: string) { this.name = name; this.works = []; } public attemptsTo(tasks: (() => Promise<void>)[]): UserActionChain { this.works.push(...tasks); return this; } public expects(expectations: (() => Promise<void>)[]): UserActionChain { this.works.push(...expectations); return this; } async run(): Promise<void> { for (const work of this.works) { await work(); } } } // 工厂函数返回链式类型,屏蔽初始实例的run方法 function createUser(name: string): UserActionChain { return new User(name); }
使用效果:
- 漏写
run()直接编译报错:await createUser("Admin").attemptsTo([...])会提示类型不存在then方法,无法直接await - 只有末尾添加
run()才会通过类型校验:await createUser("Admin").attemptsTo([...]).run()正常执行
方案2:完全省略run()调用,自动执行任务
如果不想额外写run(),可以让类实现PromiseLike接口,await实例时自动触发所有任务执行:
class User implements PromiseLike<void> { public name: string; public works: (() => Promise<void>)[]; constructor(name: string) { this.name = name; this.works = []; } public attemptsTo(tasks: (() => Promise<void>)[]): this { this.works.push(...tasks); return this; } public expects(expectations: (() => Promise<void>)[]): this { this.works.push(...expectations); return this; } // 实现PromiseLike标准接口,await时自动执行 then<TResult1 = void, TResult2 = never>( onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined ): PromiseLike<TResult1 | TResult2> { const runAllTasks = async () => { for (const work of this.works) { await work(); } }; return runAllTasks().then(onfulfilled, onrejected); } }
使用方式:
const admin = new User("Admin"); await admin .attemptsTo([EnterCredentials, Login]) .expects([LoginSuccessfully]) .attemptsTo([NavigateToUsersPage]) .expects([SeeUsersList, AddNewUser]); // 无需调用.run(),await时自动执行所有任务
内容的提问来源于stack exchange,提问作者HesamSe
相关产品推荐
相关产品推荐

