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

TypeScript中条件类型内使用this类型失效?原因及解决方法

TypeScript中this类型与条件类型结合的问题及解决方法

问题描述

尝试在父类中通过this类型结合条件类型定义抽象变量,实现自动提取当前类中数值类型属性的子集,但在子类赋值时出现类型错误。

父类与类型定义

type NumberSubsets<Subset extends Car> =
    Record<{
        [key in Exclude<keyof Subset, 'all_numbers'>]: Subset[key] extends number ? key : never;
    }[Exclude<keyof Subset, 'all_numbers'>], number>;

abstract class Car {
    public abstract all_numbers: NumberSubsets<this>;

    public doors: number;
    public is_truck: boolean;
    public wheels: number;
}

子类实现

class Sedan extends Car {
    public all_numbers: NumberSubsets<this>;

    constructor() {
        super();

        this.all_numbers = {
            doors: 5, // 此处报错
            wheels: 6
        };
    }
}

错误信息

Type '{ doors: number; wheels: number; }' is not assignable to type 'NumberSubsets<this>'.   
Object literal may only specify known properties, and 'doors' does not exist in type 'NumberSubsets<this>'

已知NumberSubsets<Sedan>可以正常工作,但希望用this简化子类的类型定义,无需手动指定具体类名。

错误原因

这是因为多态this类型在条件类型中会被延迟解析。在子类Sedan的构造函数中,this代表当前类的实例,但TypeScript无法提前确定NumberSubsets<this>的具体结构——因为this还可能被更下层的子类继承,此时NumberSubsets<this>的结果会随子类扩展而变化。因此TypeScript无法在当前上下文推断出doors和wheels是NumberSubsets<this>的合法属性。

解决方案

可以通过给抽象类添加泛型参数,将当前类的类型显式传入,让TypeScript能提前解析NumberSubsets的具体结构:

修改后的父类与子类

type NumberSubsets<Subset extends Car<Subset>> =
    Record<{
        [key in Exclude<keyof Subset, 'all_numbers'>]: Subset[key] extends number ? key : never;
    }[Exclude<keyof Subset, 'all_numbers'>], number>;

abstract class Car<T extends Car<T>> {
    public abstract all_numbers: NumberSubsets<T>;

    public doors: number;
    public is_truck: boolean;
    public wheels: number;
}

class Sedan extends Car<Sedan> {
    public all_numbers: NumberSubsets<Sedan>;

    constructor() {
        super();

        this.all_numbers = {
            doors: 5,
            wheels: 6
        };
    }
}

简化子类写法(可选)

如果不想在子类中重复写NumberSubsets<Sedan>,可以在父类中把all_numbers的类型直接关联到泛型参数T,子类只需继承时传入自身类型即可:

type NumberSubsets<Subset extends Car<Subset>> =
    Record<{
        [key in Exclude<keyof Subset, 'all_numbers'>]: Subset[key] extends number ? key : never;
    }[Exclude<keyof Subset, 'all_numbers'>], number>;

abstract class Car<T extends Car<T>> {
    public abstract all_numbers: NumberSubsets<T>;

    public doors: number;
    public is_truck: boolean;
    public wheels: number;
}

class Sedan extends Car<Sedan> {
    public all_numbers = {
        doors: 5,
        wheels: 6
    };
}

这样TypeScript会自动推断all_numbers的类型符合NumberSubsets<Sedan>的要求,同时保留了代码的简洁性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 13:03:27