一、空值问题:为什么需要非空断言?
1.1 空值的破坏力
typescript
interface User {
name: string;
age: number;
email: string;
}
function getUserName(user: User | null): string {
return user.name; // 编译错误:对象可能为"null"
}
// 运行时可能崩溃
console.log(getUserName(null).toUpperCase());
// TypeError: Cannot read properties of null
1.2 传统解决方案的局限
typescript
// 冗长的安全检查
function safeGetUserName(user: User | null): string {
if (user === null) return 'Guest';
return user.name;
}
// 可能导致虚假安全的可选链
const length = user?.name?.length || 0; // 无法区分空字符串和undefined
二、语法与使用
2.1 基本语法
typescript
interface User {
name: string;
address?: {
street: string;
};
}
// 属性断言
const userName = user!.name;
// 函数调用断言
const element = document.getElementById('app')!;
2.2 双重断言:处理复杂场景
typescript
// 当类型系统无法推断时
const inputValue = (document.getElementById('input')! as HTMLInputElement).value;
2.3 在类中的使用
typescript
class ApiClient {
private token!: string; // 明确告诉TS稍后初始化
initialize(token: string) {
this.token = token;
}
fetchData() {
// 安全使用:我们知道initialize已被调用
const headers = { Authorization: `Bearer ${this.token}` };
// ...
}
}
三、非空断言的陷阱
3.1 虚假的安全感
typescript
const users: User[] = [];
// 错误使用:数组可能为空
const firstUserName = users[0]!.name; // 运行时错误!
3.2 破坏类型安全
typescript
function getStreet(user: User): string {
return user.address!.street; // 编译通过但...
}
const user: User = { name: 'Alice' };
getStreet(user); // 运行时TypeError!
3.3 与可选链的冲突
typescript
// 危险组合:隐藏真实问题
const street = user?.address!.street;
// 当user.address为undefined时,尝试访问street会出错
总结
如果你喜欢本教程,记得点赞+收藏!关注我获取更多JavaScript开发干货。