文章目录
TypeScript 是 JavaScript 的超集,它在 JavaScript 的基础上添加了静态类型检查,极大地提升了开发者的代码质量和开发效率。其中,
null
和undefined
作为 JavaScript 中两个用于表示“值不存在”的原始类型,在 TypeScript 中也有重要的应用。本文将围绕null
和undefined
,以及它们在 TypeScript 中的使用展开讨论,并探讨strictNullChecks
这一关键选项如何影响它们的行为。
一、JavaScript 中的 null
与 undefined
在 JavaScript 中,null
和 undefined
都是表示“没有值”的两种类型。
-
null
: 是一个赋值给变量的特殊值,表示该变量现在没有任何值。它是一个有意设定的空值,通常用来指示某些事情的缺失,比如查询未找到结果等。let myVar = null;
-
undefined
: 则表示变量尚未被赋值。变量在声明但未初始化时默认值为undefined
。let anotherVar; console.log(anotherVar); // 输出 undefined
这两种值在 JavaScript 中经常用于不同的场景,但由于没有严格的类型检查机制,它们有时会导致一些难以察觉的错误。这就是 TypeScript 引入严格空检查(strictNullChecks
)的原因。
二、TypeScript 中的 null
和 undefined
在 TypeScript 中,null
和 undefined
也是原始类型,它们的使用在一定程度上取决于 TypeScript 配置中的 strictNullChecks
选项。
1. strictNullChecks
关闭时
如果 strictNullChecks
被关闭,null
和 undefined
可以被赋值给任意类型的变量。这类似于 JavaScript 的默认行为,也就是没有严格区分 null
、undefined
和其他类型。在这种模式下,可能会无意中将 null
或 undefined
分配给一个非空值,导致潜在的运行时错误。
let myString: string;
myString = null; // 在 strictNullChecks 关闭时合法
myString = undefined; // 合法
关闭 strictNullChecks
时,开发者可以更随意地处理 null
和 undefined
,但缺乏对这些特殊值的严格检查往往会导致难以调试的错误。因此,通常建议在实际项目中开启 strictNullChecks
。
2. strictNullChecks
开启时
当 strictNullChecks
选项打开时,null
和 undefined
会被视为与其他类型完全不同的类型,不能随意赋值给其他类型的变量。开发者需要在使用这些变量之前,显式地检查它们的值。这种严格的类型检查可以帮助避免由于 null
或 undefined
导致的错误。
let myString: string;
myString = null; // 错误: Type 'null' is not assignable to type 'string'
myString = undefined; // 错误: Type 'undefined' is not assignable to type 'string'
在这种情况下,必须通过类型收缩或者其他检查手段来处理可能为 null
或 undefined
的情况。例如:
function greet(name: string | null) {
if (name === null) {
console.log("Hello, guest!");
} else {
console.log(`Hello, ${name.toUpperCase()}!`);
}
}
三、非空断言运算符(Postfix !
)
有时候,我们非常确定某个变量不会是 null
或 undefined
,但 TypeScript 的类型系统无法推断出来。这时我们可以使用非空断言运算符 !
,它可以告诉编译器“我知道这个值不是 null
或 undefined
,请放心使用它”。
function processInput(input?: string | null) {
console.log(input!.toUpperCase()); // 非空断言: 告诉编译器 input 肯定不为 null 或 undefined
}
然而,非空断言运算符应当谨慎使用,因为它不会对运行时的实际值做任何检查。如果我们误用了这个运算符,在运行时输入为 null
或 undefined
时,会导致程序崩溃。
processInput(null); // 运行时错误: Cannot read property 'toUpperCase' of null
因此,尽管 !
是一个强大的工具,但在实际使用中我们应当小心,确保只有在绝对确定的情况下才使用它。
四、TypeScript 枚举类型
TypeScript 提供了 enum
关键字,允许我们定义一组命名的常量,这些常量代表特定的数值。在某些情况下,枚举类型可以帮助我们更清晰地表达代码意图。
例如,假设我们需要定义一个代表颜色的类型,我们可以通过枚举来实现:
enum Color {
Red,
Green,
Blue
}
let c: Color = Color.Green;
console.log(c); // 输出 1
枚举不仅仅是类型系统中的一种概念,它也会在 JavaScript 的运行时生成实际的代码。因此,虽然它是 TypeScript 的特性之一,但它对实际执行的代码也有影响。
字符串枚举
TypeScript 还支持字符串枚举,它与常规枚举的区别在于,它的每个枚举成员都存储为字符串常量,而不是数值。
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT"
}
let d: Direction = Direction.Left;
console.log(d); // 输出 'LEFT'
五、不常见的原始类型:bigint
和 symbol
除了常见的 null
、undefined
、number
、string
这些原始类型外,JavaScript 和 TypeScript 还支持一些不太常见的原始类型,比如 bigint
和 symbol
。
1. bigint
bigint
是 ES2020 中引入的用于表示任意精度整数的原始类型。它允许开发者处理比 number
类型更大的整数。
const largeNumber: bigint = BigInt(9007199254740991); // 通过 BigInt 函数创建
const anotherLargeNumber: bigint = 9007199254740991n; // 通过字面量语法创建
bigint
的出现解决了 JavaScript 中 number
类型最大值的限制问题(2^53 - 1
),因此在需要处理非常大的整数时,bigint
是一个理想的选择。
2. symbol
symbol
是 JavaScript 中的另一个特殊原始类型。它用于创建唯一的标识符,通常用于对象属性名,以避免属性名的冲突。
const uniqueKey1 = Symbol('key');
const uniqueKey2 = Symbol('key');
console.log(uniqueKey1 === uniqueKey2); // 输出 false
每次调用 Symbol()
时都会创建一个独一无二的 symbol
值,因此它特别适合用于需要唯一标识的场景。
六、总结
TypeScript 提供了强大的类型检查机制,帮助我们在编写代码时及早发现潜在的错误。通过 null
和 undefined
的严格类型检查,开发者可以更有效地避免许多由于空值引发的运行时错误。同时,TypeScript 还通过非空断言运算符、枚举、bigint
和 symbol
等特性扩展了 JavaScript 的能力。
推荐: