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
相关产品推荐
相关产品推荐

