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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 17:24:15