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)后,变量如果可能是 nullundefined,就必须在使用前进行显式的判断。

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

官方文档

正文

用法

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

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

  • nonNullValue: 非空值的变量。
  • Type: 期望该变量的类型。
  • value: 断言不会是nullundefined的原始值。
  • !: 告诉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);

过度承诺不好

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

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

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

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

什么时候用

适合使用的场景

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

不适合使用的场景

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

举个例子🌰:

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

总结

特点:

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

建议:

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

可能的风险:

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

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

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

相关推荐
掘金安东尼9 小时前
让 JavaScript 更容易「善后」的新能力
前端·javascript·面试
掘金安东尼9 小时前
用 HTMX 为 React Data Grid 加速实时更新
前端·javascript·面试
灵感__idea11 小时前
Hello 算法:众里寻她千“百度”
前端·javascript·算法
yinuo12 小时前
轻松接入大语言模型API -04
前端
袋鼠云数栈UED团队13 小时前
基于 Lexical 实现变量输入编辑器
前端·javascript·架构
cipher13 小时前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
UrbanJazzerati13 小时前
非常友好的Vue 3 生命周期详解
前端·面试
AAA阿giao13 小时前
从零构建一个现代登录页:深入解析 Tailwind CSS + Vite + Lucide React 的完整技术栈
前端·css·react.js
兆子龙14 小时前
像 React Hook 一样「自动触发」:用 Git Hook 拦住忘删的测试代码与其它翻车现场
前端·架构
兆子龙15 小时前
用 Auto.js 实现挂机脚本:从找图点击到循环自动化
前端·架构