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

TypeScript中如何用不同类型参数重写静态泛型方法?

问题:TypeScript继承类的静态方法类型不兼容

代码实现

基接口与类

export interface Function<T, R> {
    apply: (t: T) => R;
}

export class Function<T, R> {
    public static create<T, R>(apply: (t: T) => R): Function<T, R> {
        return new class extends Function<T, R> {
            public apply = (t: T): R => { return apply(t); };
        }();
    }
}

继承的接口与类

export interface Unary<T> extends Function<T, T> {
    apply: (t: T) => T;
}

export class Unary<T> extends Function<T, T> {
    public static create<T>(apply: (t: T) => T): Unary<T> {
        return new class extends Unary<T> {
            public apply = (t: T): T => { return apply(t); };
        }();
    }
}

错误信息

Class static side 'typeof Unary' incorrectly extends base class static side 'typeof Function'.
Types of property 'create' are incompatible.
Types of parameters 'apply' and 'apply' are incompatible.
Type 'R' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'R'.ts(2417)
function.ts(31, 29): This type parameter might need an extends T constraint.

补充说明

类和接口名称必须保持不变,因为这段代码用于模拟Java的函数式接口及其默认方法。Java可以创建这些接口的实例并自动继承默认方法,但TypeScript无法实现这一点,因此添加了工厂方法以尽可能贴近Java语义。

解决方案

问题根源在于TypeScript会检查类继承时的静态成员兼容性:Unary继承Function后,其静态方法create必须能兼容基类Function的create方法签名。基类的create允许任意输入输出类型T和R,而子类Unary的create限制了输入输出类型必须相同,导致静态方法签名不匹配。

方案1:使用declare static覆盖静态方法类型

通过手动声明子类静态方法的类型,告诉TypeScript该方法与基类兼容:

export class Unary<T> extends Function<T, T> {
    // 手动声明静态方法类型,覆盖基类的类型推断
    public static declare create<T>(apply: (t: T) => T): Unary<T>;
    public static create<T>(apply: (t: T) => T): Unary<T> {
        return new class extends Unary<T> {
            public apply = (t: T): T => apply(t);
        }();
    }
}

方案2:调整基类静态方法为多态工厂

修改基类的create方法,利用this参数指定构造函数类型,让子类可以复用基类的工厂逻辑并返回正确类型:

// 修改基类的create方法
export class Function<T, R> {
    public static create<T, R>(this: new () => Function<T, R>, apply: (t: T) => R): Function<T, R> {
        return new class extends this {
            public apply = (t: T): R => apply(t);
        }();
    }
}

// 子类复用基类工厂逻辑
export class Unary<T> extends Function<T, T> {
    public static create<T>(apply: (t: T) => T): Unary<T> {
        return super.create.apply(this, [apply]) as Unary<T>;
    }
}

方案3:类型断言简化实现

如果不需要严格的静态类型检查,也可以直接在子类create方法的返回值上使用类型断言:

export class Unary<T> extends Function<T, T> {
    public static create<T>(apply: (t: T) => T): Unary<T> {
        return new class extends Unary<T> {
            public apply = (t: T): T => apply(t);
        }() as Unary<T>;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 02:09:18