说在前面
啥是 非空断言 感叹号,啥意思。
可能看过一些代码中,很奇怪,为什么加个感叹号
,难道是什么时候不小心按了一个感叹符号,按错了吗?代码如下:
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编译器
,它一定不是空。不过承诺不要过度给,给太多不好。这个断言有可能,会存在潜在的掩盖的倾向,比如可能是你觉得就是这个一定不是空值,一定怎么怎么样。但是,这个可能只是你觉得,只是你的想法你的疏忽导致的,那么代码的安全性就降低。跟所有东西都设置成
any
anyscript差不多了。所以在使用的时候,要确保有足够的信息,去保证值一定不为空。
什么时候用
✅ 适合使用的场景:
- 在
onMounted
或nextTick
中访问 DOM ref - 确定逻辑上不可能为空的情况
- 已经进行过空值检查的代码块中
❌ 不适合使用的场景:
- 不确定值是否存在
- 在组件挂载前访问
DOM ref
- 可能接收外部不可控数据的情况
举个例子🌰:
ts
onMounted(() => {
const container = su7Ref.value! // 安全,因为已挂载
// 使用 container
// ...
})
总结
特点:
- 编译时优化 :仅
作用于类型检查
阶段,不会生成任何运行时保护代码 - 责任转移 :将空值检查的
责任
从编译器转移
到开发者身上 - 效率工具 :合理使用可以
消除冗余
的类型守卫代码
,提升
代码可读
性
建议:
- 应当作为最后的选择 ,优先考虑类型守卫或可选链(
?.
) - 最适合用于开发环境已知 而编译器无法推断的非空场景
- 在
第三方类型
定义不准确时的临时解决方案
可能的风险:
⚠️ 过度
使用会导致代码成为"定时炸弹
" - 当断言假设不成立时,错误会在运行时爆发而非编译时捕获
⚠️ 特别警惕
在异步
数据流和条件渲染
中使用非空断言
记住:每次使用 !
都应该有明确的、可验证的理由,而不是
为了"让编译器闭嘴
"的权宜之计
。