TypeScript编译通过了,接口数据为什么还会出错

举报
yd_232671198 发表于 2026/11/04 08:39:42 2026/11/04
【摘要】 接口文档写着 id 是数字,页面代码也使用了明确的 TypeScript 类型,但线上仍然出现了“无法读取空值属性”。检查响应后才发现,某个异常分支返回了 null,另一个字段则从数字变成了字符串。TypeScript 能检查代码里的类型关系,编译成 JavaScript 后,大部分类型信息已经被移除。服务器响应、浏览器存储和用户输入不会因为前端声明了一个接口,就自动符合这个接口。下面这段写...

接口文档写着 id 是数字,页面代码也使用了明确的 TypeScript 类型,但线上仍然出现了“无法读取空值属性”。检查响应后才发现,某个异常分支返回了 null,另一个字段则从数字变成了字符串。

TypeScript 能检查代码里的类型关系,编译成 JavaScript 后,大部分类型信息已经被移除。服务器响应、浏览器存储和用户输入不会因为前端声明了一个接口,就自动符合这个接口。

下面这段写法很常见,却没有验证真实数据:

interface User {
  id: number;
  name: string;
}

const user = await response.json() as User;

as User 的含义是告诉编译器“请按这个类型理解”,它不会把字符串转换成数字,也不会补齐缺失字段。给请求函数加一个泛型,通常也只是改善静态提示,不能凭空获得运行时检查。

对于结构简单的响应,可以先把外部数据当作 unknown,再用类型守卫判断。类型守卫本质上是一个返回布尔值的函数,只是它还向编译器说明:检查通过后,这个值可以按什么类型使用。

interface User {
  id: number;
  name: string;
  email?: string;
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object'
    && value !== null
    && !Array.isArray(value);
}

function isUser(value: unknown): value is User {
  if (!isRecord(value)) return false;
  return typeof value.id === 'number'
    && Number.isSafeInteger(value.id)
    && value.id > 0
    && typeof value.name === 'string'
    && (value.email === undefined || typeof value.email === 'string');
}

async function loadUser(id: number): Promise<User> {
  const response = await fetch(`/api/users/${encodeURIComponent(id)}`);
  if (!response.ok) throw new Error('用户信息请求失败');
  const value: unknown = await response.json();
  if (!isUser(value)) throw new Error('用户信息格式不符合约定');
  return value;
}

这段检查明确规定:编号必须是正的安全整数,名字必须是字符串,邮箱可以缺省。邮箱目前只检查了类型,没有验证地址格式;名字也允许空字符串。业务如果有额外要求,应在这里补上,不能因为函数叫 isUser 就默认它已经覆盖所有规则。

还要注意,JavaScript 里的 typeof null 会得到 object,因此对象检查必须排除空值。数组同样属于对象,示例也把它排除了。对于数字,单纯检查 typeof 还会放过 NaN 等特殊值,所以要根据业务选择有限数字、安全整数或其他更具体的条件。

校验通过之后,程序可以在内部沿用稳定的类型,不必每个组件都重复判断。合适的位置通常是请求层或数据适配层:外部数据刚进入应用时检查一次,把格式错误转成明确的失败状态。如果在数据深处才处理,错误可能已经传播到多个页面。

这个守卫允许出现额外字段。这对接口增加兼容字段比较友好,但如果数据用于生成签名、写入数据库或控制权限,可能还需要明确挑选允许使用的字段。通过校验也不等于可信授权,账号权限仍然必须由服务端验证。

当响应变得很深,包含多种联合结构和大量重复规则时,手写守卫容易遗漏。此时可以评估项目已有的校验库或从接口定义生成校验器,但不用为了两个简单字段立即增加新依赖。无论采用什么工具,核心都是把“声明类型”和“检查真实值”分别完成。

验证时,可以准备正常对象、null、空对象、字符串编号、负数编号和缺失可选字段这几组输入。确认错误数据在边界被拒绝,正确数据能够继续使用。比起把报错点强制断言为正确类型,这样做能让接口变化更早暴露,也更容易定位。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。