如何定义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
相关产品推荐
相关产品推荐

