TypeScript如何实现值满足基础接口同时二选一满足另外两个接口
解决方案
首先你需要结合「交叉类型+联合类型」定义目标对象的合法类型,再通过自定义类型守卫完成运行时判断和TypeScript类型收窄,具体实现如下:
步骤1:定义合法的Handler联合类型
把必须实现的OperationHandler和二选一的两个接口做组合:
type ValidOperationHandler = OperationHandler & (StatelessOperationHandler | StatefulOperationHandler);
这个类型就约束了所有合法返回值:必须同时实现OperationHandler的所有方法,且必须实现StatelessOperationHandler和StatefulOperationHandler二者之一的接口要求。
步骤2:实现自定义类型守卫
satisfies是TypeScript的编译时类型校验运算符,不能用于运行时的类型判断和收窄,你需要写类型守卫函数来完成判断:
function isStatefulOperationHandler(handler: ValidOperationHandler): handler is StatefulOperationHandler { // 运行时判断是否存在Stateful对应的方法即可 return 'GetStatefulOperation' in handler; }
步骤3:修改原有逻辑的类型定义
调整selectOperationHandler的返回值类型,以及fireOperationHandler中的判断逻辑:
// 返回值改为我们定义的合法联合类型 function selectOperationHandler(): ValidOperationHandler { // 内部实现返回对应类型的对象即可,TypeScript会自动校验返回值是否符合要求 // 示例返回一个无状态Handler return { IsCreatedByEvent(event: KeyboardEvent) { return true; }, GetStatelessOperation() { // 你的业务实现 return {} as StatelessOperation; } } } function fireOperationHandler(): void { const selectedHandler = selectOperationHandler(); if (isStatefulOperationHandler(selectedHandler)) { // 此处TypeScript会自动收窄类型为StatefulOperationHandler selectedHandler.GetStatefulOperation(); // 其他业务逻辑 } else { // 此处TypeScript会自动收窄类型为StatelessOperationHandler selectedHandler.GetStatelessOperation(); // 其他业务逻辑 } }
补充说明
如果需要严格禁止同时实现两个Handler的接口,可以用「互斥类型」做进一步约束,避免出现同时存在两个方法的非法对象:
// 定义互斥工具类型,确保两个属性不会同时存在 type Either<X, Y> = (X & Partial<Record<keyof Y, never>>) | (Y & Partial<Record<keyof X, never>>); // 改写合法Handler类型 type ValidOperationHandler = OperationHandler & Either<StatelessOperationHandler, StatefulOperationHandler>;
这个时候如果某个对象同时实现了GetStatelessOperation和GetStatefulOperation,TypeScript会直接抛出类型错误。
内容的提问来源于stack exchange,提问作者lsimmons
相关产品推荐
相关产品推荐

