TypeScript对象有值但访问属性返回undefined的原因与解决方法
问题背景
开发登录接口用户名校验逻辑时,调用数据查询方法获取用户信息后出现属性访问异常,相关代码如下:
export const signIn = async (AuthUser: IAuthUser) => { try { const userData = await execute<IAuthUser>(AuthQueries.SignIn, [AuthUser.email]); console.log(userData.email); // 输出undefined console.log(userData); // 控制台可看到对象内包含邮箱、密码相关数据 {user1email.com, password_for_user1} return userData; } catch (error) { throw error; } };
异常表现:直接打印userData时可看到对应数据,但访问userData.email属性返回undefined。
产生原因
核心问题是代码对返回数据结构的预期,和接口实际返回的结构不一致,叠加控制台打印的特性造成误导,具体分两类场景:
- 数据本身不存在可直接访问的
email属性
打印userData输出的内容为{user1email.com, password_for_user1},不符合标准JS对象{键名: 值}的结构,存在以下几种可能:- 返回值实际是数组结构(比如
["user1email.com", "password_for_user1"]),数组不存在字符串键名email,用点语法访问自然返回undefined - 返回对象的键名和预期不符:比如实际键名是
account/user_email/甚至是邮箱字符串本身,根本没有定义email这个属性 - 数据存在嵌套:
execute方法返回的是完整响应包装体,真实用户数据存放在userData.data/userData.result这类子字段下,直接访问顶层对象的email属性不存在 - 如果是GraphQL查询场景:大概率是
AuthQueries.SignIn的查询语句没有声明返回email字段,接口不会主动返回该字段
- 返回值实际是数组结构(比如
- 控制台打印的惰性求值造成误导
浏览器/Node环境下执行console.log(对象)时,不会立刻序列化对象的当前状态,控制台展示的对象内容是手动点击展开对象那一刻的最终值,不是代码执行到console.log行的即时值。很可能执行打印语句时对象还没有email属性,后续逻辑追加了相关数据,造成打印时属性已存在的错觉。
修复方案
按以下步骤排查修复:
- 第一步先获取准确的即时数据结构,不要依赖控制台展开的对象结果,执行
console.log(JSON.stringify(userData, null, 2)),该方法会序列化执行瞬间的对象结构,可直接看到实际的键名、层级、值 - 若返回值为数组结构:按索引取对应位置的值,比如邮箱在第0位时通过
userData[0]获取 - 若键名不匹配:将属性访问的键名替换为接口实际返回的名称,同步修正
IAuthUser类型定义,与接口返回字段对齐 - 若存在数据嵌套:先取出存放真实用户信息的子属性,再访问对应字段,比如
const realUser = userData.data - 若为GraphQL查询场景:检查
AuthQueries.SignIn的查询语句,在返回字段列表中显式添加email字段 - 冗余代码清理:现有逻辑中
catch (error) { throw error }属于无意义包装,删除后不影响异常向上抛出的逻辑,可直接移除简化代码。
内容的提问来源于stack exchange,提问作者Andriy Y
相关产品推荐
相关产品推荐

