如何实现集合类的流畅链式泛型map函数?子类返回类型适配
解决自定义集合类map方法返回子类实例的类型推断问题
要让自定义集合类的map方法支持流畅链式调用,并且返回当前子类的泛型实例(而不是固定的父类类型),核心是让map方法动态适配当前类的构造函数,并让TypeScript正确推断返回类型。下面分两种场景给出解决方案:
场景1:自定义集合基类(如你的Array_)
你的原始Array_类的map方法固定返回Array_<Y>,导致子类调用map时无法返回自身类型。我们可以通过动态获取当前实例的构造函数和条件类型推断来修复:
class Array_<T> { private _arr: T[]; constructor(iterable: Iterable<T>) { this._arr = [...iterable]; } [Symbol.iterator]() { return this._arr[Symbol.iterator](); } map<Y>(projector: (item: T) => Y): this extends Array_<infer _> ? Array_<Y> : never { // 动态获取当前类的构造函数(支持子类继承) const Constructor = this.constructor as new (iterable: Iterable<Y>) => Array_<Y>; // 通过生成器生成转换后的迭代器,传入构造函数创建新实例 return new Constructor((function* (source: Iterable<T>) { for (const element of source) { yield projector(element); } })(this)); } } // 子类继承Array_ class ArrayCustom<T> extends Array_<T> {} // 测试 const mappedArr = new ArrayCustom([1, 2, 3]).map(element => element.toString()); // 现在mappedArr的推断类型为ArrayCustom<string>,支持链式调用 const chained = mappedArr.map(s => s.toUpperCase()); // chained类型为ArrayCustom<string>
关键说明:
- 使用
this.constructor获取当前实例的构造函数(如果是子类调用,这里拿到的是子类的构造函数),通过类型断言让TypeScript知道它可以接受Iterable<Y>并返回对应泛型实例。 - 条件类型
this extends Array_<infer _> ? Array_<Y> : never让TypeScript自动推断返回类型为当前子类的泛型版本(比如ArrayCustom<Y>)。
场景2:继承内置Array的自定义类
如果你的ArrayCustom直接继承自内置Array,由于内置Array.prototype.map固定返回Array类型,必须重写map方法来返回自定义类实例:
class ArrayCustom<T> extends Array<T> { // 重写map方法,指定返回类型为ArrayCustom<Y> map<Y>( callbackfn: (value: T, index: number, array: T[]) => Y, thisArg?: any ): ArrayCustom<Y> { // 调用父类的map得到Array<Y>结果 const mappedResult = super.map(callbackfn, thisArg); // 利用Array构造函数的特性,传入元素创建ArrayCustom实例 return new ArrayCustom(...mappedResult); } } // 测试 const mappedArr = new ArrayCustom([1, 2, 3]).map(element => element.toString()); // mappedArr类型为ArrayCustom<string>,链式调用完全正常 const doubled = mappedArr.map(s => s.repeat(2)); // doubled类型为ArrayCustom<string>
关键说明:
- 内置
Array的map无法直接返回子类实例,所以必须重写方法,将父类返回的Array<Y>转换为ArrayCustom<Y>。 - 重写时明确指定返回类型为
ArrayCustom<Y>,确保TypeScript能正确推断链式调用的类型。
核心思路总结
无论是自定义基类还是继承内置类,要实现流畅链式调用且返回子类泛型实例,核心是:
- 让
map方法使用当前类的构造函数创建新实例,而非固定父类构造函数。 - 为TypeScript提供清晰的类型提示,确保返回类型能被正确推断。
内容的提问来源于stack exchange,提问作者prmph
相关产品推荐
相关产品推荐

