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. 效率工具 :合理使用可以消除冗余的类型守卫代码提升代码可读

建议:

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

可能的风险:

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

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

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

相关推荐
小小小小宇1 小时前
ESLint 插件笔记
前端
纪伊路上盛名在1 小时前
jupyter内核崩溃
前端·数据库·jupyter·生物信息·基因组·k-mer
Net蚂蚁代码2 小时前
Angular入门的环境准备步骤工作
前端·javascript·angular.js
小着5 小时前
vue项目页面最底部出现乱码
前端·javascript·vue.js·前端框架
lichenyang4537 小时前
React ajax中的跨域以及代理服务器
前端·react.js·ajax
呆呆的小草7 小时前
Cesium距离测量、角度测量、面积测量
开发语言·前端·javascript
一 乐8 小时前
民宿|基于java的民宿推荐系统(源码+数据库+文档)
java·前端·数据库·vue.js·论文·源码
testleaf9 小时前
前端面经整理【1】
前端·面试
好了来看下一题9 小时前
使用 React+Vite+Electron 搭建桌面应用
前端·react.js·electron
啃火龙果的兔子9 小时前
前端八股文-react篇
前端·react.js·前端框架