TypeScript递归JSONValue类型定义后使用报错,求技术解答
TypeScript递归JSONValue类型属性访问报错问题分析
问题场景
定义了带递归逻辑的JSONValue类型,初始化对象时编译器无报错,但访问对象属性时提示Property 'someString' does not exist on type '{}',函数接收该类型参数访问属性也会报错。
示例代码:
type JSONPrimitive = {} | null | undefined // any primitive, null or undefined type JSONObject = { [k: string]: JSONValue } type JSONArray = JSONValue[] type JSONValue = JSONArray | JSONObject | JSONPrimitive let myObject: JSONValue = { someString: 'it complains', someObj: { anotherString: 'why?' }, someNull: null } console.log( myObject.someString ) // ^ Error here `Property 'someString' does not exist on type '{}`
函数中访问属性的报错场景:
logMyObjectNested(myObject) // This is totally fine... function logMyObjectNested( objParam: JSONValue ) { console.log( objParam.someObj ) // ^ it complains ... }
错误原因
核心问题出在JSONPrimitive的定义上:你把{}当作原始类型的一部分,但{}在TypeScript里代表无任何属性的空对象类型,同时它是几乎所有对象类型的父类型——任何对象都能赋值给{},但{}不能赋值给有具体属性的对象类型。
当JSONValue包含JSONPrimitive(带{})时,TypeScript会优先把你的{someString: ...}这类对象匹配到{}类型,而非JSONObject。因为{}的匹配优先级更高,这就导致访问属性时,编译器认为当前值可能是没有任何属性的{},所以抛出错误。
修复方案
修正JSONPrimitive的定义,去掉{},换成JSON标准的原始类型(string、number、boolean),空对象属于JSONObject范畴,不该放到原始类型里。
修正后的代码
// 符合JSON标准的原始类型定义 type JSONPrimitive = string | number | boolean | null | undefined type JSONObject = { [k: string]: JSONValue } type JSONArray = JSONValue[] type JSONValue = JSONArray | JSONObject | JSONPrimitive let myObject: JSONValue = { someString: 'it complains', someObj: { anotherString: 'why?' }, someNull: null } // 注意:直接访问仍需类型守卫,因为JSONValue可能是数组/原始类型 if (typeof myObject === 'object' && myObject !== null && !Array.isArray(myObject)) { console.log( myObject.someString ) // 类型守卫后可安全访问 } function logMyObjectNested( objParam: JSONValue ) { // 先通过类型守卫确认是JSONObject类型 if (typeof objParam === 'object' && objParam !== null && !Array.isArray(objParam)) { console.log( objParam.someObj ) } } logMyObjectNested(myObject)
补充说明
- 修正类型后,不能直接访问
JSONValue的属性,因为它可能是数组、null或原始类型。必须通过类型守卫先确认当前值是JSONObject,才能安全访问属性。 - 最初的错误是混淆了JSON原始类型和对象类型的边界,把空对象
{}错误归类到原始类型中,导致类型匹配逻辑混乱。
内容的提问来源于stack exchange,提问作者Santiago
相关产品推荐
相关产品推荐

