TypeScript联合类型函数使用或运算符时的属性不存在问题
问题解决:TypeScript联合类型属性访问报错
错误信息翻译
类型'NotificationObjectType | ContentType | FormValues'上不存在属性'fallbackLanguage'。类型'ContentType'上不存在属性'fallbackLanguage'。
类型'NotificationObjectType | ContentType | FormValues'上不存在属性'language'。类型'NotificationObjectType'上不存在属性'language'。
问题原因
函数参数property是三种类型的联合,但这三个类型的属性不统一:
ContentType没有fallbackLanguage属性NotificationObjectType没有language属性
TypeScript的严格类型检查要求:访问联合类型的属性时,该属性必须存在于联合的所有成员中。因为它无法确定当前property具体是哪一种类型,所以不允许直接访问仅存在于部分成员的属性。
解决方案
方案1:用in操作符做类型窄化
直接通过in判断属性是否存在,以此窄化property的类型,确保访问属性时类型安全:
export const displayLanguageLabel = ( objects: { value: string; label: string }[], property: NotificationObjectType | FormValues | ContentType, ) => { let targetLang: string; if ('fallbackLanguage' in property) { // 此时property被窄化为 NotificationObjectType | FormValues targetLang = property.fallbackLanguage || property.language; } else if ('language' in property) { // 此时property被窄化为 ContentType | FormValues targetLang = property.language; } else { // 处理极端情况:如果某个类型既没有fallbackLanguage也没有language // 可根据业务需求返回undefined或抛出错误 return undefined; } return objects.find((lang) => lang.value === targetLang); };
方案2:定义类型谓词(Type Predicate)
如果需要在多个地方复用类型判断逻辑,可以自定义类型谓词函数,让类型窄化更清晰:
// 自定义类型谓词,判断对象是否有fallbackLanguage function hasFallbackLanguage(obj: unknown): obj is NotificationObjectType | FormValues { return typeof obj === 'object' && obj !== null && 'fallbackLanguage' in obj; } // 自定义类型谓词,判断对象是否有language function hasLanguage(obj: unknown): obj is FormValues | ContentType { return typeof obj === 'object' && obj !== null && 'language' in obj; } export const displayLanguageLabel = ( objects: { value: string; label: string }[], property: NotificationObjectType | FormValues | ContentType, ) => { let targetLang: string; if (hasFallbackLanguage(property)) { targetLang = property.fallbackLanguage || property.language; } else if (hasLanguage(property)) { targetLang = property.language; } else { return undefined; } return objects.find(lang => lang.value === targetLang); };
方案3:统一类型接口(推荐长期维护)
如果这三个类型都属于“包含语言信息”的对象,可以定义一个公共接口,让所有类型扩展这个接口,从根源上统一类型结构:
// 定义公共接口,包含可选的语言相关属性 interface LanguageCarrier { fallbackLanguage?: string; language?: string; } // 让你的三个类型都扩展这个接口(如果原有类型是自定义的) type NotificationObjectType = LanguageCarrier & { // 这里写NotificationObjectType原有的其他属性 id: string; // ... }; type FormValues = LanguageCarrier & { // FormValues原有的其他属性 title: string; // ... }; type ContentType = LanguageCarrier & { // ContentType原有的其他属性 content: string; // ... }; // 现在函数参数可以直接用LanguageCarrier,访问属性不会报错 export const displayLanguageLabel = ( objects: { value: string; label: string }[], property: LanguageCarrier, ) => objects.find(lang => lang.value === (property.fallbackLanguage || property.language));
内容的提问来源于stack exchange,提问作者espezaliate
相关产品推荐
相关产品推荐

