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

如何在TypeScript中传递类本身给函数并避免重复声明类型?

问题描述

我想把**类本身(而非类的实例)**作为参数传给函数,让函数能完成两个操作:1)调用该类的静态方法;2)实例化该类。

我已经实现了功能,但目前只能通过重新声明整个类结构为接口的方式实现,这导致类被重复定义——一次是class {}声明,另一次是作为函数参数的类型。

有没有办法避免这种重复,直接复用已有的类定义,不用额外重复定义类型?

以下是展示问题的可运行代码:

class Base {
    static id() { return { name: 'example', code: 'none' }; }
    static other1() { return 'example1'; }
    static other2() { return 'example2'; }
    constructor(a: number, b: number) { }
}

class A extends Base {
    static id() { return { ...super.id(), code: 'class-a' }; }
    static other1() { return 'example1A'; }
    constructor(a: number, b: number) { super(a, b + 1); }
}

class B extends Base {
    static id() { return { ...super.id(), code: 'class-b' }; }
    static other2() { return 'example2B'; }
    constructor(a: number, b: number) { super(a, b + 2); }
}

// 我必须在此重新声明所有静态函数。如何用自动从Base类生成的类型替换它?
interface BaseClassAsParameter<T> {
    new(...args: any): T;
    id: () => any;
    other1: () => any;
    other2: () => any;
    // 如果我给Base添加另一个静态函数,我也必须在这里添加它。
}

function testClass<T extends Base>(C: BaseClassAsParameter<T>): T {
    const { name, code } = C.id();
    const other1 = C.other1();
    const other2 = C.other2();

    console.log(`Test ${name} code ${code}: ${other1} ${other2}`);

    const x = new C(100, 200);
    // 对x执行一些操作
    return x;
}

testClass(A); // 应输出 "Test example code class-a: example1A example2"
testClass(B); // 应输出 "Test example code class-b: example1 example2B"
解决方案

无需手动重复定义接口,直接使用TypeScript的typeof操作符获取类自身的类型(包含所有静态成员和构造函数),即可实现复用。

步骤1:删除冗余接口

移除手动定义的BaseClassAsParameter接口,避免重复维护静态成员的类型定义。

步骤2:修改函数参数类型

将函数参数类型改为typeof Base & (new(a: number, b: number) => T),既复用Base的静态成员类型,又约束构造函数返回子类实例。

修改后的完整代码

class Base {
    static id() { return { name: 'example', code: 'none' }; }
    static other1() { return 'example1'; }
    static other2() { return 'example2'; }
    constructor(a: number, b: number) { }
}

class A extends Base {
    static id() { return { ...super.id(), code: 'class-a' }; }
    static other1() { return 'example1A'; }
    constructor(a: number, b: number) { super(a, b + 1); }
}

class B extends Base {
    static id() { return { ...super.id(), code: 'class-b' }; }
    static other2() { return 'example2B'; }
    constructor(a: number, b: number) { super(a, b + 2); }
}

// 直接复用typeof Base,无需重复定义接口
function testClass<T extends Base>(C: typeof Base & (new(a: number, b: number) => T)): T {
    const { name, code } = C.id();
    const other1 = C.other1();
    const other2 = C.other2();

    console.log(`Test ${name} code ${code}: ${other1} ${other2}`);

    const x = new C(100, 200);
    // 对x执行一些操作
    return x;
}

testClass(A); // 输出 "Test example code class-a: example1A example2"
testClass(B); // 输出 "Test example code class-b: example1 example2B"

进一步优化:自动同步构造函数参数

如果Base的构造函数参数有变动,手动写参数类型会增加维护成本,可使用ConstructorParameters<typeof Base>自动获取构造函数参数类型,让代码更健壮:

function testClass<T extends Base>(C: typeof Base & (new(...args: ConstructorParameters<typeof Base>) => T)): T {
    const { name, code } = C.id();
    const other1 = C.other1();
    const other2 = C.other2();

    console.log(`Test ${name} code ${code}: ${other1} ${other2}`);

    const x = new C(100, 200);
    return x;
}

原理说明

  • typeof Base获取Base类自身的类型,包含所有静态方法和构造函数的定义
  • new(...args: ...) => T约束构造函数必须返回T类型的实例(T是Base的子类)
  • 两者结合后,参数C既可以调用Base的所有静态方法,又能实例化出子类对象

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 19:30:35