如何让TypeScript函数正确接收链式修饰器数组并实现类型校验
链式函数修饰器的TypeScript类型校验实现
完全可行,通过TypeScript的泛型与条件类型,可以精准追踪链式修饰器的输入输出类型,确保只有合法的修饰器序列能通过类型校验,同时正确推断最终返回值的类型。
实现方案
首先定义两个辅助类型,用于串联函数链并推断最终结果类型:
// 递归校验修饰器链的合法性:每个后续函数的输入必须匹配前一个的输出 type ChainableModifiers<T extends any[]> = T extends [infer First, ...infer Rest] ? First extends (data: infer In) => infer Out ? Rest extends ChainableModifiers<Rest> ? Rest extends [(data: Out) => infer NextOut, ...infer RestRest] ? [(data: In) => Out, ...ChainableModifiers<[(data: Out) => NextOut, ...RestRest]>] : [(data: In) => Out] : never : never : []; // 提取修饰器链最终的返回值类型 type ChainResult<T extends any[]> = T extends [...infer _, (data: infer In) => infer Out] ? Out : {};
然后修改func函数,添加严格的泛型约束:
const func = <T extends ChainableModifiers<T>>(modifiers: T): ChainResult<T> => { return modifiers.reduce((acc, modifier) => modifier(acc), {} as any); };
测试验证
使用你提供的修饰器函数进行测试:
const addA = (data: {}) => { return { ...data, a: "test" }; }; const addB = (data: {}) => { return { ...data, b: "test" }; }; const updateA = (data: { a: string }) => { return { ...data, a: `${data.a} test` }; }; console.log(func([addA])); // ✅ 类型校验通过,返回类型为 { a: string } console.log(func([addA, addB])); // ✅ 类型校验通过,返回类型为 { a: string, b: string } console.log(func([addA, addB, updateA])); // ✅ 类型校验通过,updateA的输入匹配前序结果 console.log(func([updateA])); // ❌ 类型校验报错:初始值{}不符合updateA的输入要求(需要{a: string})
原理说明
ChainableModifiers通过递归遍历修饰器数组,强制每个后续函数的输入类型与前一个函数的输出类型匹配,非法序列会直接触发类型错误。ChainResult自动提取最后一个修饰器的输出类型,让func的返回值类型完全符合链式调用后的实际数据结构。- 泛型约束
T extends ChainableModifiers<T>确保只有合法的修饰器链能被传入func,从根源上避免运行时因数据结构不匹配导致的错误。
内容的提问来源于stack exchange,提问作者kennarddh
相关产品推荐
相关产品推荐

