如何让TypeScript自动推断属性非null/undefined?
让TypeScript自动推断属性非空的替代方案
你的问题核心在于:settings是一个getter属性,每次访问this.settings都会重新执行findOne()逻辑,TypeScript的静态分析无法跨函数跟踪它的状态——哪怕你在upsert里检查过this.settings不为null,到update方法里再次调用getter时,TypeScript无法保证结果还是非空的,所以必须用!断言。
要让TypeScript自动推断,最直接的解决方式是把getter的结果缓存到变量中,传递给后续方法,而不是依赖多次调用getter。
修改后的代码示例
type UpsertRequestType = { per_page?: number; page_window?: number; }; type SettingsCollectionType = { _id: string; per_page: number; page_window: number; }; class Settings { constructor(private readonly settingsRepository: Mongo.Collection<SettingsCollectionType>) {} private get settings() { return this.settingsRepository.findOne({}) || null; } upsert(payload: Optional<UpsertRequestType>): void; upsert(payload: Required<UpsertRequestType>): void; upsert(payload: unknown): void { // 仅调用一次getter,将结果缓存到变量中 const currentSettings = this.settings; if (currentSettings) { return this.update(currentSettings, payload as Optional<UpsertRequestType>); } return this.insert(payload as Required<UpsertRequestType>); } // 直接接收已确认非空的settings对象 private update(currentSettings: SettingsCollectionType, payload: Optional<UpsertRequestType>): void { this.settingsRepository.update({ _id: currentSettings._id }, { $set: payload }); } private insert(payload: Required<UpsertRequestType>): void { this.settingsRepository.insert(payload); } }
为什么这个方案有效?
- 我们在
upsert里只调用一次this.settings,并将结果存入currentSettings变量。TypeScript能跟踪这个变量的类型:当if (currentSettings)为真时,变量类型会被窄化为SettingsCollectionType(而非SettingsCollectionType | null)。 - 把这个已窄化类型的变量传递给
update方法,TypeScript明确知道currentSettings._id肯定存在,无需任何断言。
其他可选思路
如果你的业务场景允许,可以将settings从getter改为私有成员变量,在类初始化或首次使用时加载并缓存,这样后续访问时TypeScript能直接推断其非空状态。但这种方式适合不需要实时获取最新数据的场景:
class Settings { private settings: SettingsCollectionType | null = null; constructor(private readonly settingsRepository: Mongo.Collection<SettingsCollectionType>) { // 初始化时加载一次 this.loadSettings(); } private async loadSettings() { this.settings = await this.settingsRepository.findOne({}) || null; } // 后续方法中使用this.settings时,若已确认加载完成,TypeScript可推断非空 }
内容的提问来源于stack exchange,提问作者n1md7
相关产品推荐
相关产品推荐

