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

如何用映射类型扩展/合并TypeScript类的原型?

类型扩展问题:基于映射类型扩展类原型的TS类型定义

简化示例

function Base<T extends Record<string, Function>>(record: T) {
    class X {
        constructor() { }
    }
    // (A) 将record中的所有函数添加到原型中。
    // 实际中我会使用`Object.defineProperty`或类似方法,此处不影响问题核心。
    Object.assign(X.prototype, record)

    // (???) 如何编写类型,让TS知道X.prototype拥有更多成员?

    return X;
}

// (B) Derived继承自Base的返回值,同时传入`foo`和`bar`函数供Derived“继承”。
class Derived extends Base({
    foo: () => 42,
    bar: () => "hi"
}) {
    // (C) 我希望在此处重写函数
    override bar() {
        return "bye";
    }
}

const inst = new Derived();

// (D) 会打印`42, "bye"`,但TS无法识别.foo()
console.log(inst.foo(), inst.bar())

当前代码在(C)和(D)处报错,因为TS无法识别(A)中对原型的修改。实际场景中Base会根据传入的record生成原型方法,需要TS识别基于T的映射类型(如Transformed<T>)。

已尝试的方案

尝试1:内部合并X的声明

试图通过声明合并让TS识别X拥有T的成员,但无法运行:

function Base<T extends Record<string, Function>>(record: T) {
    class X { constructor() { } }
    Object.assign(X.prototype, record)

    // 错误:Interface 'X' incorrectly extends interface 'T'.
    interface X extends T {}

    return X;
}

尝试2:断言返回包含T实例的构造函数

此方案基本可用,但TS会认为T的成员属于实例而非原型,导致重写方法时报错:

function Base<T extends Record<string, Function>>(record: T) {
    class X { constructor() { } }
    Object.assign(X.prototype, record)

    return X as new () => X & T;
}

重写时的错误:

class Derived extends Base({
    foo: ():number => 42,
    bar: ():string => "hi"
}) {
    // 报错:Class 'Base<{ foo: () => number; bar: () => string; }>.X & { foo: () => number; bar: () => string; }'
    // defines instance member property 'bar', but extended class 'Derived' defines
    // it as instance member function.
    override bar() {
        return "bye";
    }
}

虽然将函数改为字段可以解决,但会在每个实例创建新函数,无法复用原型上的函数,不够理想。

尝试3:断言返回构造函数并扩展prototype类型

此方案无法生效,TS要求Derived自行实现T,与意图不符:

function Base<T extends Record<string, Function>>(record: T) {
    class X { constructor() { } }
    Object.assign(X.prototype, record)

    return X as typeof X & { prototype: X & T };
}

补充完整示例

核心差异是使用映射类型Transformed<T>描述原型中实际需要的属性类型:

type Fn = (x: {}) => unknown;
type Transformed<T extends Record<string, Fn>> = {
  // 此函数类型是原型中的实际类型。
  [K in keyof T]: () => ReturnType<Fn>
}

具体问题

  1. 一般情况下,如何用映射类型T扩展/合并类的类型?
    这类场景经常遇到:有一个计算类型T(通常是映射类型或约束泛型),需要将其与类的类型合并,上述示例是具体场景。
  2. 在本示例中,如何为Base(或X)编写类型,让TS知道返回的类的原型中包含T的属性?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 15:50:53