如何禁止Foo子类重写init方法时返回Promise<any>(Foo非抽象类)
解决方案
泛型约束+any类型拦截
修改基类Foo,引入泛型参数并配合工具类型,从根源上禁止子类将init的返回类型设为Promise<any>:
// 工具类型:排除any类型,若传入any则返回never type NotAny<T> = T extends any ? (unknown extends T ? never : T) : T; class Foo<T = void> { async init(): Promise<NotAny<T>> { return undefined as NotAny<T>; } } // 合法示例:返回Promise<number> class Bar extends Foo<number> { async init(): Promise<number> { return 3; } } // 合法示例:返回Promise<string> class Baz extends Foo<string> { async init(): Promise<string> { return "hello"; } } // 非法示例:尝试返回Promise<any>,TypeScript会直接报错 class InvalidBar extends Foo<any> { async init(): Promise<any> { return {}; } }
核心逻辑
NotAny<T>通过条件类型判断:如果T是any,则返回never,否则返回T。当子类指定泛型为any时,基类的init返回类型会变为Promise<never>,与子类的Promise<any>类型不兼容,触发类型错误。- 泛型参数默认值设为
void,完全保留基类原有行为,不需要修改Foo的业务逻辑。
备选方案:返回类型协变+类型校验
如果不想引入泛型,也可以利用TypeScript的返回类型协变特性,配合工具类型限制:
class Foo { async init(): Promise<unknown> { return undefined; } } // 工具类型:拦截Promise<any> type ForbidAnyPromise<T> = T extends Promise<any> ? never : T; // 合法示例:返回Promise<number>(协变兼容Promise<unknown>) class Bar extends Foo { async init(): Promise<number> { return 3; } } // 非法示例:返回Promise<any>会触发类型错误 class InvalidBar extends Foo { async init(): ForbidAnyPromise<Promise<any>> { return {}; } }
核心逻辑
- TypeScript允许返回类型协变,
Promise<number>/Promise<string>等可以兼容基类的Promise<unknown>,但Promise<any>会被ForbidAnyPromise映射为never,强制子类无法使用该类型。
内容的提问来源于stack exchange,提问作者Miguel
相关产品推荐
相关产品推荐

