You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript返回未知键对象数组时访问属性报错的解决方法

TypeScript迁移数据库查询函数的最佳实现方案

TypeScript 本身无法静态解析SQL语句的逻辑,自然没法自动推断查询返回对象的具体字段结构,这类场景下改造成本最低、实用性最强的方案是给查询函数增加泛型支持,由调用方在调用时指定单次查询的结果行类型,同时兼容存量未改造的JS代码。

改造查询函数类型定义

给原有query函数增加泛型参数,设置默认值为通用对象类型,保证老代码不需要立刻修改也不会触发类型报错,支持渐进式迁移:

/**
 * 对当前连接的数据库执行查询
 * @param sql 待执行的SQL查询语句
 * @param params 预处理语句对应的参数数组
 * @returns 查询结果构成的对象数组,查询完成后resolve
 */
const query = async <T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T[]> => {
  // 原有数据库操作逻辑保持不变即可
}

调用时指定返回类型

在调用query的位置,传入本次查询对应的结果行类型,TypeScript就能正确识别返回对象的字段,不会抛出属性不存在的类型错误。以计数查询场景为例,改造后写法如下:

// 定义本次查询返回的行结构
type CountResult = {
  cnt: number
}
const result = await query<CountResult>('SELECT count(*) as cnt from Table where id=?', [2])
// 此处TS可正确推导result[0]上存在cnt字段,无类型报错
return result[0].cnt

迁移注意事项

  • 泛型仅在编译阶段提供类型校验和提示,不会对运行时返回的数据做结构校验。如果对数据可靠性要求高,可以搭配轻量结构校验库,在查询结果返回后做格式校验,避免SQL字段名写错、查询逻辑变更导致的线上问题。
  • 项目中高频复用的查询结果结构,可以抽成公共类型定义(比如用户表行类型UserRow、计数结果类型CountResult),减少重复的类型声明代码。
  • 存量代码不需要一次性改造完成,未传入泛型参数的调用点,返回值默认为Record<string, unknown>类型,可以在后续迭代中逐步补全类型。

可选:带运行时校验的严谨实现

如果需要同时兼顾编译时类型提示和运行时数据安全,可以结合结构校验库做一层封装,示例写法如下:

import { z } from 'zod'

// 同时定义运行时校验规则和TS类型
const CountResultSchema = z.object({
  cnt: z.number()
})
type CountResult = z.infer<typeof CountResultSchema>

const result = await query<CountResult>('SELECT count(*) as cnt from Table where id=?', [2])
// 运行时校验数据结构,不符合预期直接抛错,同时自动推导TS类型
const validResult = CountResultSchema.parse(result[0])
return validResult.cnt

内容的提问来源于stack exchange,提问作者Steffen Nieuwenhoven

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 19:54:23