如何让TypeScript识别类型检查?解决动态属性访问类型报错
解决TypeScript动态获取对象属性的类型收窄问题
你遇到的问题核心是TypeScript无法通过typeof判断来正确收窄自定义类的类型,同时也没有建立property参数与对象属性类型的关联关系,导致类型检查报错。下面先分析错误原因,再给出具体的解决方法。
错误原因解析
- TS2339错误:当进入
else分支时,TypeScript依然认为obj[property]的类型是number | Color——因为typeof对自定义类实例返回的是"object",虽然你知道此时值是Color,但TS无法通过typeof的判断结果直接推导出这一点,所以不允许调用toArray方法。 - TS2322错误:当
property为'color'时,obj[property]是Color类型,而函数返回类型定义为number | number[],Color与这两个类型都不兼容,因此报错。
解决方案
方案一:自定义类型守卫明确区分类型
通过instanceof判断是否为Color实例,并编写类型谓词让TypeScript识别类型:
class Color { r: number g: number b: number constructor(r: number, g: number, b: number) { this.r = r; this.g = g; this.b = b; } toArray() { return [this.r, this.g, this.b]; } } interface MyObject { intensity: number, color: Color, } type ObjectProperty = 'intensity'|'color' // 自定义类型守卫函数 function isColor(value: number | Color): value is Color { return value instanceof Color; } const myFunc = (obj: MyObject, property: ObjectProperty): number|number[] => { const value = obj[property]; if (typeof value === 'number') { return value; } else if (isColor(value)) { return value.toArray(); } // 处理理论上不可能出现的情况,避免TS报错 throw new Error(`Invalid property type for ${property}`); }
方案二:用泛型关联属性与返回类型
这种方法能让函数返回类型与传入的property严格对应,提供更精确的类型提示:
class Color { r: number g: number b: number constructor(r: number, g: number, b: number) { this.r = r; this.g = g; this.b = b; } toArray() { return [this.r, this.g, this.b]; } } interface MyObject { intensity: number, color: Color, } type ObjectProperty = 'intensity'|'color' // 定义属性到返回类型的映射 type PropertyReturnMap = { intensity: number; color: number[]; }; const myFunc = <K extends ObjectProperty>(obj: MyObject, property: K): PropertyReturnMap[K] => { const value = obj[property]; if (property === 'intensity') { return value; } else { return value.toArray(); } } // 使用示例: const testObj: MyObject = { intensity: 0.7, color: new Color(255, 0, 0) }; const intensity = myFunc(testObj, 'intensity'); // 类型自动推导为number const colorArr = myFunc(testObj, 'color'); // 类型自动推导为number[]
方案三:用in操作符直接检查属性
通过检查toArray属性是否存在,让TypeScript自动收窄类型:
class Color { r: number g: number b: number constructor(r: number, g: number, b: number) { this.r = r; this.g = g; this.b = b; } toArray() { return [this.r, this.g, this.b]; } } interface MyObject { intensity: number, color: Color, } type ObjectProperty = 'intensity'|'color' const myFunc = (obj: MyObject, property: ObjectProperty): number|number[] => { const value = obj[property]; if (typeof value === 'number') { return value; } else if ('toArray' in value) { return value.toArray(); } throw new Error(`Unexpected property type for ${property}`); }
总结
原来的代码无法通过typeof让TS识别Color类型,因为自定义类实例的typeof结果是"object",而非类本身的类型。上面三种方法都能解决这个问题,其中泛型方案的类型提示最精确,类型守卫方案适合需要复用类型判断的场景,in操作符方案则最简单直接。
内容的提问来源于stack exchange,提问作者sauermar
相关产品推荐
相关产品推荐

