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

如何用TypeScript泛型实现工作流步骤类型强兼容?

TypeScript 类型安全的工作流泛型实现

基础类型定义

先明确核心的Step接口和示例数据类型:

// 空输入标记类型
type None = undefined;
// 示例数据类型
type RandomNumber = number;
type Int = number;

// 步骤接口:定义输入输出类型约束
interface Step<TInput, TOutput> {
  execute(input: TInput): TOutput;
}

类型安全的工作流泛型约束

要让编译器自动校验步骤间的输入输出兼容性,核心是利用可变参数泛型+递归类型约束,强制后续步骤的输入类型匹配前一步的输出类型。

我们通过工具类型和静态构造方法实现这一约束:

// 工具类型:提取Step的输入类型
type StepInput<S extends Step<any, any>> = S extends Step<infer I, any> ? I : never;
// 工具类型:提取Step的输出类型
type StepOutput<S extends Step<any, any>> = S extends Step<any, infer O> ? O : never;

// 递归约束:确保工作流步骤的输入输出依次匹配
type ValidWorkflowSteps<T extends Step<any, any>[]> = 
  T extends [infer First extends Step<any, any>, ...infer Rest extends Step<any, any>[]]
    ? Rest extends [infer Next extends Step<any, any>, ...infer RestRest]
      ? StepOutput<First> extends StepInput<Next>
        ? [First, ...ValidWorkflowSteps<[Next, ...RestRest]>]
        : never
      : T
    : T;

// 工作流类
class Workflow<Steps extends Step<any, any>[]> {
  private steps: Steps;

  private constructor(steps: Steps) {
    this.steps = steps;
  }

  // 静态构造方法:仅接受类型合法的步骤序列
  static create<Steps extends Step<any, any>[]>(
    ...steps: ValidWorkflowSteps<Steps>
  ): Workflow<Steps> {
    return new Workflow(steps);
  }

  // 执行工作流:自动推导初始输入和最终输出类型
  run(initialInput: StepInput<Steps[0]>): StepOutput<Steps[Steps['length'] - 1]> {
    return this.steps.reduce((acc, step) => step.execute(acc), initialInput as any);
  }
}

示例验证

实现用户给出的三个步骤类:

class InitRandom implements Step<None, RandomNumber> {
  execute(input: None): RandomNumber {
    return Math.random() * 100;
  }
}

class Floor implements Step<RandomNumber, Int> {
  execute(input: RandomNumber): Int {
    return Math.floor(input);
  }
}

class Square implements Step<Int, Int> {
  execute(input: Int): Int {
    return input * input;
  }
}

合法工作流(编译器通过)

// 步骤顺序正确,输入输出类型完全匹配
const validWorkflow = Workflow.create(new InitRandom(), new Floor(), new Square());
// 初始输入为None类型(undefined),最终输出为Int类型
const result = validWorkflow.run(undefined); // result 类型为 Int

非法工作流(编译器报错)

// 步骤顺序错误:Floor的输入是RandomNumber,但作为第一步需要接受None类型的初始输入
const invalidWorkflow = Workflow.create(new Floor(), new InitRandom(), new Square());
// 编译器直接报错:类型'Step<RandomNumber, Int>'的参数不能赋给类型'never'的参数

核心逻辑说明

  • ValidWorkflowSteps递归遍历步骤数组,只要某一步的输入与前一步的输出不匹配,整个类型就会变为never,触发编译器错误。
  • StepInput和StepOutput通过类型推断,从Step实例中提取对应的输入输出类型。
  • run方法利用数组索引类型,自动推导工作流的初始输入类型和最终输出类型,无需手动指定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 13:07:46