ts 非空 断言, 后缀加感叹号!,有话要说!!!

说在前面

啥是 非空断言 感叹号,啥意思。

可能看过一些代码中,很奇怪,为什么加个感叹号,难道是什么时候不小心按了一个感叹符号,按错了吗?代码如下:

ts 复制代码
<template>
  <div>
    <div ref="container"></div>
  </div>
</template>

<script setup lang="ts" name="">
const container = ref<HTMLDivElement>()

const init = () => {
  const container = container.value!
  container.appendChild(xxx)
}

onMounted(() => {
  init()
})
</script>

当开启了严格的空值检查(strictNullChecks)后,变量如果可能是 null 或 undefined,就必须在使用前进行显式的判断。

! 操作符是 TypeScript 提供的一个"逃生舱",为了在某些场景下简化代码,ts 提供了非空断言操作符(! 后缀符号),用来告诉编译器:"我确定这个值不是 null 或 undefined。",确保逻辑上真的不会出现空值情况。

官方文档

正文

用法

ts 复制代码
const nonNullValue: Type = value!;

感叹号 !没有写错,它 是 TypeScript 的非空断言操作符(Non-null Assertion Operator)。

  • nonNullValue: 非空值的变量。
  • Type: 期望该变量的类型。
  • value: 断言不会是null或undefined的原始值。
  • !: 告诉ts编译器,这个值一定不是空值。
ts 复制代码
let name: string | null = "Jackie";
console.log(name!.length); // 告诉可以放心大胆地用`length`这个属性
ts 复制代码
// 有时候可能有null或者undefined的情况,但是你保证这个时候绝对不是空值,就可以用

function getElementById(id: string): HTMLElement | null {
    return document.getElementById(id);
}
 
const element = getElementById('myElement')!;
element.style.color = 'red';

作用

ts 复制代码
const container = ref<HTMLDivElement>()

container.value 的类型是 HTMLDivElement | undefined,

因为:

  • 在组件挂载前,ref 的值是 undefined。
  • 只有在 DOM 元素被创建并绑定后,才会有实际的 HTMLDivElement 值。

如果代码写成:

ts 复制代码
const init = () => {
  const container = container.value
  container.appendChild(xxx)
}

编辑器就会飘红:

它的意思就是说,你这里定义的container除了HTMLDivElement这种情况,还有undefined这种情况。

所以需要非空断言。

ts 复制代码
const container = container.value! // 类型: HTMLDivElement

在这个例子中,通过container.value!告诉编译器,container.value变量在使用时一定不是null一定不是undefined,可以安全地去使用appendChild这个方法。

解构也可以用

js 复制代码
interface User {
    name: string | null;
    age: number;
}
 
const user: User = { 
    name: "Alice", 
    age: 30 
};
const { name!, age } = user;
console.log(name);

过度承诺不好

在解构赋值时,如果某个属性可能为null或undefined,但你确定在当前上下文中它一定有值,可以使用非空断言。

注意: 就是承诺给ts编译器,它一定不是空。不过承诺不要过度给,给太多不好。这个断言有可能,会存在潜在的掩盖的倾向,比如可能是你觉得就是这个一定不是空值,一定怎么怎么样。

但是,这个可能只是你觉得,只是你的想法你的疏忽导致的,那么代码的安全性就降低。跟所有东西都设置成anyanyscript差不多了。

所以在使用的时候,要确保有足够的信息,去保证值一定不为空。

什么时候用

✅ 适合使用的场景:

  • 在 onMounted 或 nextTick 中访问 DOM ref
  • 确定逻辑上不可能为空的情况
  • 已经进行过空值检查的代码块中

❌ 不适合使用的场景:

  • 不确定值是否存在
  • 在组件挂载前访问 DOM ref
  • 可能接收外部不可控数据的情况

举个例子🌰:

ts 复制代码
onMounted(() => {
  const container = su7Ref.value!  // 安全,因为已挂载
  // 使用 container
  // ...
})

总结

特点:

  1. 编译时优化 :仅作用于类型检查阶段,不会生成任何运行时保护代码
  2. 责任转移 :将空值检查的责任从编译器转移到开发者身上
  3. 效率工具 :合理使用可以消除冗余的类型守卫代码,提升代码可读性

建议:

  • 应当作为最后的选择 ,优先考虑类型守卫或可选链(?.)
  • 最适合用于开发环境已知 而编译器无法推断的非空场景
  • 在第三方类型定义不准确时的临时解决方案

可能的风险:

⚠️ 过度使用会导致代码成为"定时炸弹" - 当断言假设不成立时,错误会在运行时爆发而非编译时捕获

⚠️ 特别警惕在异步数据流和条件渲染中使用非空断言

记住:每次使用 ! 都应该有明确的、可验证的理由,而不是为了"让编译器闭嘴"的权宜之计。

相关推荐
子兮曰5 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰5 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万5 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝5 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋5 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁5 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95275 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大5 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师5 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学5 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端