TypeScript访问Sequelize查询返回对象新增price属性报ts2339错误如何解决
报错根因
- 调用
findAll时配置了raw: true,实际返回的是普通JS对象而非Crypto模型实例,但TypeScript默认推导的返回类型仍是Crypto[],和实际结构不匹配 - 生成
toClient数组的逻辑中,第一条返回原始查询对象,其余返回新增了price属性的扩展对象,TypeScript推导出的数组元素类型是「原始对象 | 带price的扩展对象」联合类型,原始对象不存在price属性,因此访问时触发类型报错 - 额外逻辑问题:你当前的代码第一条数据没有
price属性,后续返回给客户端时第一条的price会是undefined,不符合预期
解决方案
最优方案:统一结构+显式声明类型
步骤1:定义相关类型
// 首先定义currency的合法值类型 type Currency = 'BTCUSD' | 'ETHUSD' | 'LTCUSD'; // 定义raw查询返回的原始数据结构 type RawPriceRow = { [key in Currency]: number } & { createdAt: Date; }; // 定义处理后的数据结构,统一包含price属性 type ProcessedPriceRow = RawPriceRow & { price: number; };
步骤2:查询时显式指定返回类型
因为开启了raw: true,给findAll传入泛型指定返回的是RawPriceRow数组,而非默认的Crypto实例数组:
const allPrices = await Crypto.findAll<RawPriceRow>({ attributes: [currency, 'createdAt'], order: [['createdAt', 'ASC']], raw: true });
步骤3:统一处理逻辑,给所有项新增price属性
修正原逻辑中第一条没有price的问题,显式声明toClient的类型为ProcessedPriceRow[]:
const toClient: ProcessedPriceRow[] = allPrices.map((item, index) => { return { ...item, // 第一条的price直接取自身对应货币的数值,和后续规则对齐即可 price: index === 0 ? +item[currency] : +item[currency] + +allPrices[0][currency], } });
步骤4:返回给客户端时不再报错
此时TypeScript已经明确知道toClient的每个元素都有price属性,访问不会触发报错:
res.status(200).send({ success: true, message: "Successfully retrieved Historic prices", data: toClient.map((price) => ({ price: price.price, createdAt: price.createdAt, })), });
临时兼容方案:类型守卫
如果你不想修改原有逻辑,一定要保留第一条不带price的结构,可以在访问price时加类型守卫判断:
res.status(200).send({ success: true, message: "Successfully retrieved Historic prices", data: toClient.map((price) => ({ price: 'price' in price ? price.price : +price[currency], createdAt: price.createdAt, })), });
不推荐的快速方案:类型断言
如果只是临时解决报错不考虑长期类型安全,可以直接用类型断言跳过校验:
res.status(200).send({ success: true, message: "Successfully retrieved Historic prices", data: toClient.map((price) => ({ price: (price as {price: number}).price, createdAt: price.createdAt, })), });
内容的提问来源于stack exchange,提问作者user16657995
相关产品推荐
相关产品推荐

