如何用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
相关产品推荐
相关产品推荐

