You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现集合类的流畅链式泛型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能正确推断链式调用的类型。

核心思路总结

无论是自定义基类还是继承内置类,要实现流畅链式调用且返回子类泛型实例,核心是:

  1. 让map方法使用当前类的构造函数创建新实例,而非固定父类构造函数。
  2. 为TypeScript提供清晰的类型提示,确保返回类型能被正确推断。

内容的提问来源于stack exchange,提问作者prmph

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:44:54