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

TypeScript:基于elseOp是否定义的条件类型实现问题

问题

我正在创建一系列继承抽象类Operation<T, R>的类,该类定义了方法perform(t: T): R。
我希望实现一个条件操作类ConditionalOperation<T, R> extends Operation<T, T | R>,其构造函数签名如下:

constructor(
    private predicate: (value: T) => boolean,
    private thenOp: Operation<T, R>,
    private elseOp?: Operation<T, R>
) {
    super();
}

该类的perform方法逻辑如下:

  • 若elseOp已定义,当断言为真时将输入值传给thenOp,否则传给elseOp。
  • 若elseOp未定义,当断言为真时将输入值传给thenOp,否则直接返回输入值。

这种行为决定了ConditionalOperation签名中的T | R:当elseOp定义时返回类型为R,否则为T | R。我尝试通过条件类型实现这种依赖于elseOp是否定义的返回类型校验,编写了对应代码,但TypeScript不允许在elseOp未定义时返回t,尽管此时对应的返回类型应为T | R。

请问除了创建两个条件类之外,还有其他实现方式吗?

解决方案

可以通过方法重载或泛型条件类型两种方式实现,无需拆分多个类。


方式一:利用perform方法重载

直接给perform定义不同的重载签名,让TypeScript根据elseOp的存在自动推断返回类型:

abstract class Operation<T, R> {
  abstract perform(t: T): R;
}

class ConditionalOperation<T, R> extends Operation<T, T | R> {
  constructor(
    private predicate: (value: T) => boolean,
    private thenOp: Operation<T, R>,
    private elseOp?: Operation<T, R>
  ) {
    super();
  }

  // 重载签名1:传入elseOp时,返回类型为R
  perform(t: T): R;
  // 重载签名2:未传入elseOp时,返回类型为T | R
  perform(t: T): T | R;
  // 方法实现
  perform(t: T): T | R {
    if (this.predicate(t)) {
      return this.thenOp.perform(t);
    } else {
      // 使用可选链和空值合并简化逻辑
      return this.elseOp?.perform(t) ?? t;
    }
  }
}

类型验证

// 场景1:无elseOp,返回number | string
const op1 = new ConditionalOperation(
  (num: number) => num > 0,
  new class extends Operation<number, string> {
    perform(t: number): string { return t.toString(); }
  }
);
const res1 = op1.perform(-1); // 类型为number | string

// 场景2:有elseOp,返回string
const op2 = new ConditionalOperation(
  (num: number) => num > 0,
  new class extends Operation<number, string> { perform(t) { return t.toString(); } },
  new class extends Operation<number, string> { perform(t) { return `neg: ${t}`; } }
);
const res2 = op2.perform(-1); // 类型为string

方式二:泛型条件类型+构造函数重载

通过泛型参数标记elseOp的类型,结合条件类型精确控制返回值:

abstract class Operation<T, R> {
  abstract perform(t: T): R;
}

// 定义条件类型:根据elseOp是否为undefined决定返回类型
type ConditionalResult<T, R, E> = E extends undefined ? T | R : R;

class ConditionalOperation<T, R, E extends Operation<T, R> | undefined = undefined>
  extends Operation<T, ConditionalResult<T, R, E>> {

  // 构造函数重载1:传入elseOp
  constructor(
    predicate: (value: T) => boolean,
    thenOp: Operation<T, R>,
    elseOp: Operation<T, R>
  );
  // 构造函数重载2:不传入elseOp
  constructor(
    predicate: (value: T) => boolean,
    thenOp: Operation<T, R>
  );
  // 构造函数实现
  constructor(
    private predicate: (value: T) => boolean,
    private thenOp: Operation<T, R>,
    private elseOp?: E
  ) {
    super();
  }

  perform(t: T): ConditionalResult<T, R, E> {
    if (this.predicate(t)) {
      return this.thenOp.perform(t) as ConditionalResult<T, R, E>;
    } else {
      if (this.elseOp) {
        return this.elseOp.perform(t) as ConditionalResult<T, R, E>;
      } else {
        return t as ConditionalResult<T, R, E>;
      }
    }
  }
}

这种方式的类型推断更严格,能在编译阶段就明确区分两种场景的返回类型。


内容的提问来源于stack exchange,提问作者Aisteru Firë

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 12:46:25