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

TypeScript如何返回具体子类实例而非抽象类类型

问题描述

在子类WorldDetail中,我在pages属性内定义了页面名称与对应具体类的键值映射。在抽象基类中编写了getPage方法,用于根据传入的名称获取对应具体类的实例。目前调用时仅能访问抽象类与子类共有的方法,无法调用仅子类存在的专属方法(如subFunc)。
实现需要满足以下约束:

  • 不得将子类专属方法声明为抽象基类的抽象方法
  • 不得对getPage返回的实例做显式类型强转为具体子类
    附初始复现代码:
abstract class Page {
    public share = () => {
        return "shared";
    }
}

class DetailPage extends Page {
    public share = () => {
        return "reshared";
    }
    public subFunc = () => {
        return "Sub func"
    }
}

type PageDerived = {new (): Page} & typeof Page;

type PageObj = {
  [key: string]: PageDerived
}

abstract class WorldBase {
    protected abstract get pages(): PageObj;

    public getPage(pageName: string): InstanceType<PageDerived> {
        const SubPage = this.pages[pageName];
        const sub = new SubPage();
        return sub; // 推导类型为基类Page,丢失子类专属方法
    }
}

class WorldDetail extends WorldBase {
    override get pages() {
        return {
            "DetailPage": DetailPage
        }
    }
}

const w = new WorldDetail();
const page = w.getPage("DetailPage"); // 类型被推导为Page,不是DetailPage
console.log("DEBUG share", page.share())
// console.log("DEBUG sub", page.subFunc()); // 类型报错,无法调用子类专属方法
解决方案

通过泛型绑定子类页面映射的类型,让TS自动推导返回实例的具体类型,完全满足约束要求,修改后可直接运行的代码如下:

abstract class Page {
    public share = () => {
        return "shared";
    }
}

class DetailPage extends Page {
    public share = () => {
        return "reshared";
    }
    public subFunc = () => {
        return "Sub func"
    }
}

// 基类增加泛型参数,绑定子类pages映射的具体类型
abstract class WorldBase<T extends Record<string, new () => Page>> {
    protected abstract get pages(): T;

    // 方法增加泛型参数,根据传入的页面名自动推导返回实例类型
    public getPage<K extends keyof T>(pageName: K): InstanceType<T[K]> {
        const SubPage = this.pages[pageName];
        return new SubPage();
    }
}

class WorldDetail extends WorldBase<{
    "DetailPage": typeof DetailPage
}> {
    override get pages() {
        return {
            "DetailPage": DetailPage
        }
    }
}

const w = new WorldDetail();
const page = w.getPage("DetailPage"); // 自动推导为DetailPage类型
console.log("DEBUG share", page.share())
console.log("DEBUG sub", page.subFunc()); // 直接调用,无类型报错

实现说明

  • 给抽象基类WorldBase增加泛型参数T,约束为「页面名 -> 对应Page子类构造函数」的映射结构,子类继承时传入自身pages的具体类型即可
  • getPage方法增加泛型参数K,为传入页面名的字面量类型,返回值直接取映射中对应key的构造函数的实例类型,TS会自动完成类型推导
  • 这套实现既不需要在基类提前声明子类的专属方法,也不需要调用时手动做类型断言,同时TS还会自动校验子类pages返回的结构是否和泛型定义一致,避免写错页面名或者对应类的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 09:45:38