07.TypeScript never类型、symbol类型
1. never 类型
never类型表示那些永不存在的值的类型。例如,never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。
1.1 实例
// never类型的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {
}
}
console.log("never类型的函数调用");
// error("这里会抛出异常"); // 调用这行会抛出异常
// fail(); // 调用这行也会抛出异常
// infiniteLoop(); // 调用这行会进入无限循环
1.2 fail 推断返回值类型为 never
1.3 never 类型可以赋值给任何类型
never 类型可以赋值给任何类型
function throwError(): never {
throw new Error('This function never returns')
}
// never 类型可以赋值给任何类型
let anyValue: any = throwError()
let stringValue: string = throwError()
let numberValue: number = throwError()
let booleanValue: boolean = throwError()
let objectValue: object = throwError()
let arrayValue: any[] = throwError()
1.4 其他类型不能赋值给 never 类型
1.5 总结
- never 类型表示永远不会出现的值;
- 通常用于函数的返回类型,表示函数永远不会正常返回;
- 当函数总是会抛出异常或无限循环时,其返回值类型就是 never;
- never 类型可以赋值给任何类型,但除了 never 本身外,其他任何类型都不能赋值给 never 类型。
2. void类型
void 类型表示没有任何类型。当一个函数没有返回值时,其返回值类型就是 void。
2.1 实例
// void类型的函数没有返回值
function warnUser(): void {
console.log("This is my warning message");
}
// 声明一个void类型的变量
let unusable: void = undefined;
// unusable = null; // 在严格模式下会报错
console.log("void类型的函数调用");
warnUser();
2.2 在严格模式下会报错
2.3 输出结果
2.4 总结
- void 类型表示没有任何类型;
- 当一个函数没有返回值时,其返回值类型就是 void;
- void 类型的变量只能赋值为 undefined 或 null(在非严格模式下);
- void 类型主要用于函数没有返回值的情况。
3. never与void的差异
- 定义:never类型表示永远不会出现的值,通常用于函数永远不会正常返回的情况(如抛出异常或无限循环);void类型表示没有任何类型,用于函数没有返回值的情况。
- 赋值:never类型可以赋值给任何类型,但除了never本身外,其他任何类型都不能赋值给never类型;void类型的变量只能赋值为undefined或null(在非严格模式下),其他类型不能赋值给void类型。
- 使用场景:never类型用于函数永远不会正常返回的情况;void类型用于函数没有返回值的情况。
- 示例:never类型的函数如
function error(message: string): never { throw new Error(message); };void类型的函数如function warnUser(): void { console.log("This is my warning message"); }。
4. symbol类型
symbol 是 ES6 引入的一种原始数据类型,表示独一无二的值。它是 JavaScript 语言的第七种数据类型。
4.1 实例
// 创建symbol
let s1 = Symbol();
let s2 = Symbol();
console.log(typeof s1); // 输出: symbol
console.log(s1.toString()); // 输出: Symbol()
// Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述
let s3 = Symbol('key');
let s4 = Symbol('key');
console.log(s3 === s4); // 输出: false
// 作为属性名的Symbol
let mySymbol = Symbol();
// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';
// 第二种写法
let b = {
[mySymbol]: 'Hello!'
};
// 第三种写法
let c = {};
Object.defineProperty(c, mySymbol, { value: 'Hello!' });
console.log(a[mySymbol]); // 输出: Hello!
console.log(b[mySymbol]); // 输出: Hello!
console.log(c[mySymbol]); // 输出: Hello!
4.2 Symbol 的值是唯一的
var s3 = Symbol('key');
var s4 = Symbol('key');
console.log(s3 === s4); // 输出: false
4.3 输出结果
4.4 Symbol 值不能与其他类型的值进行运算
try {
var s5 = Symbol('test');
// @ts-ignore: 这里故意演示错误用法
console.log(s5 + 'hello'); // 这会抛出 TypeError
}
catch (e) {
console.log('Symbol 不能与字符串相加:', e.message);
}
// 尝试将 Symbol 与数字相加
try {
var s6 = Symbol('number');
// @ts-ignore: 这里故意演示错误用法
console.log(s6 + 10); // 这会抛出 TypeError
}
catch (e) {
console.log('Symbol 不能与数字相加:', e.message);
}
// 尝试将 Symbol 与布尔值比较
try {
var s7 = Symbol('boolean');
// @ts-ignore: 这里故意演示错误用法
console.log(s7 == true); // 这会返回 false 而不是抛出错误
}
catch (e) {
console.log('Symbol 与布尔值比较:', e.message);
}
// 正确的 Symbol 比较方式
var s8 = Symbol('comparison');
var s9 = Symbol('comparison');
console.log('不同的 Symbol 比较:', s8 === s9); // 输出: false
console.log('相同的 Symbol 比较:', s8 === s8); // 输出: true
4.5 输出结果
4.6 Symbol 值可以显式转为字符串
// Symbol 值可以显式转为字符串
let s10 = Symbol('string-conversion')
// 使用 toString() 方法
console.log('使用 toString() 方法:', s10.toString()) // 输出: Symbol(string-conversion)
// 使用 String() 函数
console.log('使用 String() 函数:', String(s10)) // 输出: Symbol(string-conversion)
// 获取 Symbol 的描述
console.log('Symbol 的描述:', s10.description) // 输出: string-conversion
4.7 输出结果
4.8 Symbol 值可以转为布尔值,但不能转为数值
// Symbol 值可以转为布尔值,但不能转为数值
let s11 = Symbol('boolean-and-number')
// 转为布尔值 (始终为 true)
console.log('Symbol 转布尔值:', Boolean(s11)) // 输出: true
console.log('Symbol 转布尔值 (!!)', !!s11) // 输出: true
// 尝试转为数值 (会抛出 TypeError)
try {
// @ts-ignore: 这里故意演示错误用法
console.log('Symbol 转数值:', +s11) // 这会抛出 TypeError
} catch (e) {
console.log('Symbol 不能转为数值:', e.message)
}
try {
// @ts-ignore: 这里故意演示错误用法
console.log('Symbol 转数值 (Number):', Number(s11)) // 这会返回 NaN
} catch (e) {
console.log('Symbol 不能转为数值 (Number):', e.message)
}
4.9 输出结果
4.10 总结
- symbol 是 ES6 引入的一种原始数据类型,表示独一无二的值;
- Symbol 函数前不能使用 new 命令,否则会报错;
- Symbol 函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时使用;
- Symbol 值不能与其他类型的值进行运算,会报错;
- Symbol 值可以显式转为字符串;
- Symbol 值也可以转为布尔值,但不能转为数值;
- Symbol 值作为对象属性名时,不能用点运算符;
- Symbol 值作为属性名时,该属性是公有属性,可以在类的外部访问。
5. 总结
- never类型表示永不存在的值的类型,常用于函数返回值类型,表示函数永远不会正常返回;
- void类型表示没有任何类型,用于函数没有返回值的情况;
- symbol类型表示独一无二的值,是ES6引入的一种原始数据类型;
- never类型可以赋值给任何类型,但除了never本身外,其他任何类型都不能赋值给never类型;
- void类型的变量只能赋值为undefined或null(在非严格模式下);
- Symbol值作为对象属性名时,可以保证不会出现同名的属性;
- Symbol值不能与其他类型的值进行运算,会报错;
- Symbol值可以显式转为字符串和布尔值,但不能转为数值;
- never与void的主要区别在于:never用于函数永远不会正常返回的情况,而void用于函数没有返回值的情况。