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

如何封装new关键字且不丢失构造类型的泛型参数

TypeScript构造函数传入通用函数时保留自动类型推导的方法

我希望将构造函数及其参数传入一个通用函数,同时返回结果不丢失类型信息,但当前实现的类型推导不符合预期:

const _new = <A, B>(a: A[], b: new (a: A[]) => B) => new b(a)
const set = _new([1, 2], Set) // 得到类型 Set<unknown>,但期望是 Set<number>

直接调用构造函数时类型推导正常:

const set = new Set([1, 2]) // 类型为 Set<number>

手动指定泛型可以解决,但我希望实现自动推导:

const set = _new([1, 2], Set<number>) // 类型为 Set<number>

问题原因

问题出在SetConstructor的重载定义上。当两个重载合并后,TypeScript无法正确从数组参数推导泛型T,但单独使用任意一个重载都能得到正确的Set<number>类型:

interface SetConstructor {
  new <T>(iterable?: Iterable<T> | null): Set<T>
}
interface SetConstructor {
  new <T = any>(values?: readonly T[] | null): Set<T>
  readonly prototype: Set<any>
}

解决方案

通过TypeScript内置的ConstructorParameters和InstanceType工具类型,将函数泛型与构造函数的参数、实例类型关联,即可实现自动推导:

通用实现(保持原调用顺序)

const _new = <C extends new (...args: any[]) => any>(arg: ConstructorParameters<C>[0], ctor: C): InstanceType<C> => {
  return new ctor(arg)
}

// 测试
const set = _new([1, 2], Set) // 自动推导为 Set<number>
const map = _new([[1, 'a'], [2, 'b']], Map) // 自动推导为 Map<number, string>

更灵活的多参数版本

如果需要支持构造函数接收多个参数,可以调整为:

const _new = <C extends new (...args: any[]) => any>(ctor: C, ...args: ConstructorParameters<C>): InstanceType<C> => {
  return new ctor(...args)
}

// 测试
const set = _new(Set, [1, 2]) // 自动推导为 Set<number>
const date = _new(Date, 2024, 5, 1) // 自动推导为 Date

原理说明

  • ConstructorParameters<C>:提取构造函数C的参数类型组成元组
  • InstanceType<C>:提取构造函数C的实例类型
  • 泛型C extends new (...args: any[]) => any限制传入的必须是构造函数

通过这种方式,TypeScript可以根据传入的构造函数和参数,双向推导正确的实例类型,解决重载导致的推导失效问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 00:16:06