TypeScript泛型类:如何让getSmth方法根据泛型类型按需抽象
嘿,这个问题挺有意思的!你想要的效果是让泛型基类根据T是否为默认的{},自动切换getSmth方法的行为——要么提供默认实现,要么强制子类重写。你原来的代码之所以没生效,是因为不管T是什么类型,父类都给了getSmth的具体实现,TypeScript自然不会要求子类重写啦。
下面给你两种可行的实现方式:
方法一:通过类型别名选择不同基类
这种方式最直接,我们定义两个基类:一个给T={}的情况提供默认实现,另一个给其他T定义抽象方法,然后用条件类型让Base根据T自动选择继承哪个类:
// 当T是{}时的基类,包含getSmth的默认实现 abstract class BaseWithDefault { public getSmth(): {} { return {}; } } // 当T不是{}时的抽象基类,强制子类实现getSmth abstract class BaseWithAbstract<T> { public abstract getSmth(): T; } // 根据泛型T的类型,选择对应的基类 type Base<T = {}> = T extends {} ? {} extends T ? BaseWithDefault : BaseWithAbstract<T> : BaseWithAbstract<T>; // 测试用例 class A extends Base<{}> { // 不需要重写getSmth,继承了BaseWithDefault的实现 } class B extends Base<{ x: number }> { // 必须重写getSmth,否则TypeScript会报错 public getSmth(): { x: number } { return { x: 42 }; } }
方法二:利用条件类型和类型不匹配强制重写
如果不想拆分多个基类,也可以在单个基类里通过条件类型让默认实现的返回类型在T≠{}时不匹配,从而强制子类重写:
abstract class Base<T = {}> { // 当T是{}时返回{},否则返回never(让默认实现类型不合法) public getSmth(): T extends {} ? {} extends T ? {} : never : never { // 运行时判断,仅当T是{}时返回默认值 return {} as any; } } class A extends Base<{}> { // 正常使用,无需重写 } class B extends Base<{ x: number }> { // 必须重写getSmth,否则调用时会出现类型错误(返回never无法赋值给{ x: number }) public getSmth(): { x: number } { return { x: 123 }; } }
原理说明
第一种方法的核心是用条件类型动态选择基类:当T严格等于{}(即T extends {}且{} extends T)时,继承带默认实现的类;否则继承带抽象方法的类,TypeScript会自动强制子类实现抽象方法。
第二种方法则是利用类型不匹配:当T≠{}时,父类getSmth的返回类型是never,而子类需要返回T类型的值,所以必须重写方法来修正类型,否则会触发类型错误。
两种方法都能满足你的需求,第一种更直观,类型提示也更清晰,推荐使用~
内容的提问来源于stack exchange,提问作者Qwertiy
相关产品推荐
相关产品推荐

