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

如何定义TypeScript方法返回类型,基于参数类型推断属性存在性?

问题:TypeScript类型守卫精准推断指定属性非undefined

我定义了Design类,其中checkFetched方法用于检查实例中指定的Filename类型属性是否存在DesignData值。当前实现的问题是:调用该方法后,TypeScript会错误地将所有属性都推断为非undefined,但我需要仅让被检查的属性被推断为非undefined,其他属性仍保留可能为undefined的状态。

原始代码

type Filename = 'original' | 'result'
type DesignData = {
  id: string
  // ...
}

export class Design {
  original?: DesignData
  result?: DesignData

  checkFetched(target: Filename): this is { [K in typeof target]: DesignData } {
    return !!this[target]
  }

  private async loadDesign(fileName: Filename) {
    if (!this.checkFetched(fileName)) return
    const shouldNotHaveUndefined = this[fileName]
    const shouldHaveUndefined1 = this.original
    const shouldHaveUndefined2 = this.result
  }

  private async loadDesign2() {
    if (!this.checkFetched('original')) return
    const shouldNotHaveUndefined = this.original
    const shouldHaveUndefined = this.result
  }
}

问题分析

当前的类型守卫this is { [K in typeof target]: DesignData }会直接替换整个this的类型,TypeScript会认为所有属性都符合该索引签名,导致未被检查的属性也被误判为非undefined。

解决方案

修改checkFetched的类型守卫返回值,通过交叉类型+Omit实现仅窄化目标属性的类型,保留其他属性的原有可选性:

type Filename = 'original' | 'result'
type DesignData = {
  id: string
  // ...
}

export class Design {
  original?: DesignData
  result?: DesignData

  checkFetched<T extends Filename>(target: T): this is Omit<this, T> & { [K in T]: DesignData } {
    return !!this[target]
  }

  private async loadDesign(fileName: Filename) {
    if (!this.checkFetched(fileName)) return
    const shouldNotHaveUndefined = this[fileName] // 类型:DesignData
    const shouldHaveUndefined1 = this.original // 类型:DesignData | undefined
    const shouldHaveUndefined2 = this.result // 类型:DesignData | undefined
  }

  private async loadDesign2() {
    if (!this.checkFetched('original')) return
    const shouldNotHaveUndefined = this.original // 类型:DesignData
    const shouldHaveUndefined = this.result // 类型:DesignData | undefined
  }
}

说明

  • Omit<this, T>保留了类中除目标属性T之外的所有属性的原始类型(包括可选性)
  • { [K in T]: DesignData }将目标属性T的类型窄化为非undefined的DesignData
  • 交叉类型&将两者合并,实现仅精准窄化目标属性的效果

内容的提问来源于stack exchange,提问作者Nathan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 05:49:56