给 AI 返回数据加 TS 类型:别全标 any
AI接口开发中一个常见误区:将返回值统一标注any类型,流式chunk亦是如此,直至字段错误在运行时暴露。本文基于团队早期实践,总结补齐TypeScript类型时遇到的几个关键问题。

先给流式 chunk 定结构
后端每条 SSE data 块的结构是固定的,先将其定义为 interface:
复制代码interface StreamChunk {
id: string
choices: {
delta: { content?: string; role?: string }
finish_reason: string | null
}[]
}
需注意content字段为可选属性。流式传输中,部分chunk仅包含role(如首条数据),另一些只有finish_reason(如末尾数据)。若未标记为可选,类型解析将无法匹配。
parse 后别直接信
JSON.parse的返回值类型为any。直接使用as StreamChunk进行类型断言并不能真正保护代码安全—当后端实际返回结构异常时,类型系统依然默许,运行时错误仍会发生。建议使用zod进行运行时校验,或至少编写守卫函数:
复制代码function isChunk(x: unknown): x is StreamChunk {
return typeof x === 'object' && x !== null && 'choices' in x
}
类型断言仅能欺骗编译器,运行时校验才是真正的安全保障,二者不可混淆。
AI 返回结构化数据更要类型
让AI返回JSON(如抽取出的字段)是最具挑战的场景。AI偶尔会遗漏字段,或将数字返回为字符串。针对这类返回定义类型时,建议将所有字段标为可选并设置兜底默认值,确保渲染过程中具备容错能力:
复制代码interface Extracted {
name?: string
amount?: number // AI 可能返回 "100" 字符串,得自己转
}
切勿假设AI会完全遵循给定的schema返回,必须承认其偶发的不可预测性。
给 hook 也标好类型
封装的useChat等hook,其入参、返回的messages及状态机status,应全部标注为字面量联合类型:
复制代码type Status = 'idle' | 'streaming' | 'error'
将status的类型限定为'idle' | 'streaming' | 'error'而非string后,若switch分支遗漏某个状态,编译器会及时提醒,避免大量低级错误。
一个偷懒处
后端接口未能通过OpenAPI工具自动生成类型,而是手动编写interface。当后端字段发生变更时,前端类型无法同步更新,需人工跟进。推荐使用schema进行自动生成,但相关流程尚未搭建。
为流式chunk和结构化数据定义精准类型,并结合运行时校验,可有效规避AI返回数据中的类型陷阱,提升联调效率。如何为AI返回数据建立类型安全保障,值得深入探讨。