TypeScript自定义PipeLine类报错:无法找到名称'R',求解决方案
Puppeteer爬虫Pipeline类实现问题修正
问题背景
我正在用Puppeteer开发网页爬虫,想要实现一个PipeLine类:
- 接收Puppeteer的
Page实例 - 暴露
add方法,接收PipeLineFn类型的函数数组 - 按顺序调用这些函数,前一个函数的Promise结果作为下一个的参数
- 最终返回所有任务完成的Promise
尝试的实现代码:
import { Page } from 'puppeteer'; type PipeLineFn = <T>(arg: Page, output?: Promise<T>) => Promise<T>; type ReturnFnType<T> = T extends <R>( arg: Page, output?: Promise<R> ) => Promise<R> ? R : any; export class PipeLine { output?: Promise<ReturnFnType<PipeLineFn>>; constructor(private page: Page) {} public add(args: (PipeLineFn | undefined)[]) { const toBeDone = args.map(fn => { if(fn === undefined) return undefined; this.output = this.__add__(fn, this.page, this.output); return this.output; }); return Promise.all(toBeDone); } private __add__ = <T>(fn: PipeLineFn, page: Page, output?: Promise<T>) => fn(page, output); } // 调用示例 // const pipe = new PipeLine(page); // page来自Puppeteer // await pipe.add([setAllCookies, openLoginPage]);
预期结果:add()按顺序执行任务,前一个函数的Promise结果可传给下一个函数使用。
错误信息:ReturnFnType中出现Cannot find name 'R'错误。
错误原因
- 泛型作用域问题:在
ReturnFnType的条件类型中,<R>是函数内部的泛型参数,这个参数的作用域仅限于条件判断里的函数类型,外部无法访问,所以TypeScript报错找不到R。而且这个类型设计完全没必要,因为PipeLineFn的泛型是每个函数独立的,类的output不需要提前固定类型。 - 执行逻辑错误:原代码用
map处理函数数组,会同时触发所有函数执行,无法实现顺序调用的需求,Promise.all只是等待所有并行任务完成,不符合你要的“前一个完成再执行下一个”的流水线逻辑。
修正后的实现
import { Page } from 'puppeteer'; // 调整PipeLineFn类型:前一个函数的返回值(非Promise)作为下一个的输入 type PipeLineFn<T = unknown, R = unknown> = (page: Page, prevResult?: T) => Promise<R>; export class PipeLine { private currentResult: unknown; constructor(private page: Page) {} // 接收PipeLineFn数组,顺序执行 public async add(fns: (PipeLineFn | undefined)[]): Promise<unknown> { for (const fn of fns) { if (!fn) continue; // 等待前一个函数完成,传递结果给下一个 this.currentResult = await fn(this.page, this.currentResult); } // 返回最终结果 return this.currentResult; } } // 调用示例(假设的函数实现) async function setAllCookies(page: Page): Promise<string> { await page.setCookie({ name: 'token', value: '123' }); return 'cookie-set'; } async function openLoginPage(page: Page, prevResult?: string): Promise<boolean> { console.log('上一步结果:', prevResult); // 输出"cookie-set" await page.goto('https://example.com/login'); return page.url() === 'https://example.com/login'; } // 使用方式 // const pipe = new PipeLine(page); // const finalResult = await pipe.add([setAllCookies, openLoginPage]);
关键改进点
- 类型优化:重新定义
PipeLineFn,让前一个函数的返回值(解析后的Promise结果)作为下一个函数的输入,类型更清晰合理。 - 顺序执行:用
for...of循环替代map,确保每个函数等待前一个完成后再执行,真正实现流水线逻辑。 - 移除冗余类型:删掉了不必要的
ReturnFnType,用unknown处理中间结果,让类型自然流动。
内容的提问来源于stack exchange,提问作者Harit Joshi
相关产品推荐
相关产品推荐

