前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库TypeScript unknown 对象校验 类型守卫
TyTypeScript类型系统基础

TypeScript 如何把 unknown 安全收窄为业务对象,而不是直接断言?

安全收窄需要回答具体检查了什么,不能只在返回类型中写下一个业务接口。

前端进阶之旅 · 一题精讲更新于 2026.09.06
TypeScript#类型系统基础#类型系统
先看核心答案读代码示例
理解线索

把证据建立在使用之前

  1. 容器检查排除 null 并确认是可以检查属性的对象
  2. 字段检查验证存在性、基础类型和领域取值限制
  3. 结果构造将已经确认的字段交给后续业务逻辑

校验范围应覆盖返回类型承诺的内容;不能把只验证局部字段的函数声明成完整解析器。

核心回答

先记住这个答案

将 unknown 变成业务对象,应先确认非空对象,再检查所需属性是否存在、字段值的类型和业务限制,最后返回经过整理的结果。简单边界可以用普通解析函数,复用判断也可以写类型谓词,但谓词实现必须与它承诺的完整类型一致。只检查一个标签就断言整个复杂对象,仍可能遗漏嵌套字段、数组元素和数值范围。解析失败应有明确错误路径,成功结果可以重新构造,避免把未知额外字段和共享可变引用直接带入内部。

  • 先证明容器可检查,再逐个证明字段可用
  • 类型谓词的返回签名不会替作者验证实现
  • 解析函数可以同时校验并构造干净的内部对象

对象检查需要拆成可证明的步骤

typeof 的 object 分支仍包含 null,数组也属于对象,因此具体协议如果不接受数组,应额外排除。通过容器检查以后,属性存在只能证明这个键可读,不能证明它的值就是数字。把每一步证据写清楚,编译器与维护者才能跟上解析过程。

示例只承诺返回一个正整数用户标识和非空名称。它验证了容器、两个字段的基础类型以及必要的业务范围,再构造一个新对象。额外字段不会被自动复制,非法输入则立即进入明确的错误路径,调用方无需在每次读取时重复猜测结构。

解析一份明确而有限的用户契约TypeScript
type UserSummary = { id: number; name: string };
function parseUser(value: unknown): UserSummary {
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
    throw new TypeError('user must be an object');
  }
  if (!('id' in value) || typeof value.id !== 'number' ||
      !Number.isSafeInteger(value.id) || value.id <= 0) {
    throw new TypeError('invalid user id');
  }
  if (!('name' in value) || typeof value.name !== 'string' || !value.name.trim()) {
    throw new TypeError('invalid user name');
  }
  return { id: value.id, name: value.name.trim() };
}

合法对象会得到仅包含两个字段的新结果,空值、数组、非整数标识和空白名称会被拒绝。这里按普通解析数据设计,若输入可能是带副作用的访问器或 Proxy,还需要限定输入来源与读取方式。

类型谓词为什么也可能撒谎

返回 value is UserSummary 的函数会让编译器信任判断结果,但函数体并不会自动被证明等价于整个接口。实现如果永远返回 true,后续代码依然可能获得错误的安全感。谓词既要考虑成功分支,也要确认失败分支所表达的排除是否合理。

复杂结构包含数组和嵌套对象时,要继续验证元素和子字段。Array.isArray 只证明容器是数组,不能证明每项都是用户。若规则多、错误提示需要定位字段路径,可以使用明确的解析器组合方式,避免一个巨大布尔表达式难以审查和维护。

校验后是否还会失去保证

如果返回原对象引用,其他持有者随后修改字段,先前校验建立的事实可能失效。按需要重新构造不可变视图或复制必要层级,可以减少这种共享写入问题;但浅复制只隔离顶层,嵌套数据仍应根据契约处理。

校验失败时可以抛错,也可以返回带成功标签的结果联合,关键是调用者必须处理失败。接口边界的错误信息应帮助定位字段与原因,同时避免把整个敏感输入原样写进日志。解析器测试应同时覆盖合法样本、缺字段、错误类型和业务边界。

回答前,多想一步

容易答错的地方

检查 typeof 是 object 就能当业务接口
对象分支还可能包含空值与数组,具体字段和领域限制也未得到证明;需要按后续实际读取的契约逐步检查。
类型谓词有类型签名就不会写错
编译器会信任谓词所声明的关联,不能自动证明所有业务条件;应审阅实现并用错误输入验证每个承诺的字段。
试着用自己的话回答

面试官还会怎么问?

校验函数必须返回原输入对象吗?

不必,解析函数可以返回清理后的新对象,统一格式并丢弃不需要的字段;如果要保留引用身份,应明确后续可变性与所有权。

属性存在检查会接受继承属性吗?

in 会沿原型链检查,因此不是自有属性证明;普通 JSON 数据通常没有自定义原型来源,其他输入则需要额外明确自有属性政策。

为什么已经校验 number 还检查整数范围?

number 包含小数、无穷和非数等值,而业务标识通常要求正的安全整数;基础类型证明与领域有效性检查承担不同责任。

从一道题,走向一组知识

把知识连起来

类型系统基础

TypeScript 的 unknown 和 any 有什么区别,外部数据应该用哪个?

理解为什么未知输入应保留使用前检查的责任

类型收窄

TypeScript 的 in 如何收窄联合类型,可选属性为什么可能出现在两边?

仔细区分属性存在、可选属性与属性值类型

参考资料

  • TypeScript:Narrowing
  • TypeScript:Unlisted Property Narrowing with in

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 对象检查需要拆成可证明的步骤
  3. 类型谓词为什么也可能撒谎
  4. 校验后是否还会失去保证
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑