TypeScript如何实现支持任意数量函数的类型安全链式调用方法
TypeScript 类型安全的任意长度函数链(函数组合)实现
基于 TypeScript 4.1+ 支持的递归条件类型、可变元组泛型,可以实现任意长度的类型安全chain函数,不需要写固定数量的重载。
1. 定义基础类型和工具类型
// 基础单入参单返回值函数类型 type Fn<I, O> = (input: I) => O // 提取函数链的入参类型:即第一个函数的入参类型 type ChainInput<Fns extends Fn<any, any>[]> = Fns extends [] ? unknown : Fns extends [Fn<infer I, any>, ...infer _Rest] ? I : never // 提取函数链的返回值类型:即最后一个函数的返回值类型 type ChainOutput<Fns extends Fn<any, any>[]> = Fns extends [] ? unknown : Fns extends [...infer _Rest, Fn<any, infer O>] ? O : never // 校验函数链合法性:相邻函数的前一个返回值必须匹配后一个入参 type ValidateChain<Fns extends Fn<any, any>[]> = Fns extends [] ? [] : Fns extends [Fn<any, any>] ? Fns : Fns extends [Fn<infer I, infer O>, Fn<infer NextI, infer NextO>, ...infer Rest extends Fn<any, any>[]] ? O extends NextI ? [Fn<I, O>, ...ValidateChain<[Fn<NextI, NextO>, ...Rest]>] : [{ error: `类型不匹配:前一个函数返回类型 ${O} 与后一个函数入参类型 ${NextI} 不兼容` }] : Fn<any, any>[]
2. 实现chain函数
function chain<Fns extends Fn<any, any>[]>( ...fns: ValidateChain<Fns> extends Fns ? Fns : ValidateChain<Fns> ): Fn<ChainInput<Fns>, ChainOutput<Fns>> { return (input) => { let result = input for (const fn of fns) { result = fn(result) } return result } }
3. 效果验证
正常使用场景
const toNumber: Fn<string, number> = (input) => parseInt(input) const toBoolean: Fn<number, boolean> = (input) => input > 0 const toString: Fn<boolean, string> = (input) => input.toString() // 自动推导chained类型为 Fn<string, string> const chained = chain(toNumber, toBoolean, toString) const result = chained('5') // 类型推导为string,运行值为"true"
错误使用场景
如果函数顺序不对、参数不匹配,TypeScript会直接抛出类型错误:
// 编译阶段直接报错,提示类型不匹配 const wrongChained = chain(toBoolean, toNumber, toString)
方案优势
- 支持任意长度的单入参单返回值函数链式组合
- 自动校验相邻函数的出参、入参兼容性,提前发现类型错误
- 自动推导最终组合后函数的入参和返回值类型,无需手动声明
内容的提问来源于stack exchange,提问作者Balázs Édes
相关产品推荐
相关产品推荐

