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

建议:

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

可能的风险:

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

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

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

相关推荐
冰暮流星18 小时前
css之动画
前端·css
jump68018 小时前
axios
前端
spionbo18 小时前
前端解构赋值避坑指南基础到高阶深度解析技巧
前端
用户40993225021218 小时前
Vue响应式声明的API差异、底层原理与常见陷阱你都搞懂了吗
前端·ai编程·trae
开发者小天18 小时前
React中的componentWillUnmount 使用
前端·javascript·vue.js·react.js
永远的个初学者19 小时前
图片优化 上传图片压缩 npm包支持vue(react)框架开源插件 支持在线与本地
前端·vue.js·react.js
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ19 小时前
npm i / npm install 卡死不动解决方法
前端·npm·node.js
Kratzdisteln19 小时前
【Cursor _RubicsCube Diary 1】Node.js;npm;Vite
前端·npm·node.js
杰克尼19 小时前
vue_day04
前端·javascript·vue.js
明远湖之鱼20 小时前
浅入理解跨端渲染:从零实现 React DSL 跨端渲染机制
前端·react native·react.js