简介TypeScript 是 JavaScript 的一个超集,它通过添加静态类型来增强语言能力。这些类型可确保更好的代码质量和可读性。
在 TypeScript 中,了解any、unknown和never类型之间的区别对于开发人员(尤其是初学者)是非常重要的事情。
在本文中,我将以清晰、直接的方式介绍这三种类型。您将了解每种类型代表什么、何时使用它们以及将它们合并到您的 TypeScript 项目中的实际意义。在本文结束时,相信您将对 any、never和unknown有扎实的了解,从而使您能够在 TypeScript 开发中就类型使用做出更明智的决定。
现在就让我们深入探索这些关键类型。
在 TypeScript 中声明基本类型
在深入了解、和的具体细节之前any,unknown了解neverTypeScript 如何处理基本类型声明会很有帮助。这些基础知识将使您更容易掌握更复杂的类型
TypeScript 允许你明确定义变量的类型。下面简要介绍一下在TypeScript 中如何声明具有基本类型的变量:
// 数字
let age : number = 30 ;
// 字符串
let name : string = "Alice" ;
// 布尔值
let isActive : boolean = true ;
// 数组
let numbers : number [] = [ 1 , 2 , 3 ];
// 元组
let person : [ string , number ] = [ "Alice" , 30 ];
// 枚举
enum Color { Red , Green , Blue }
let c : Color = Color . Green ;
解释
上面这些声明中的每一个变量都将与特定类型相关联,以确保始终为其分配正确类型的值。
现在,您有了这种理解,我们现在就可以继续探索更复杂的类型any、unknown与never。
1、any:灵活类型
TypeScript 中的any类型允许您像使用变量时可以分配任何数据类型。
即您可以将字符串、数字、布尔值、对象或任何其他类型分配给使用any声明的变量。当不需要或不切实际地执行严格类型时,此类型非常有用,可为函数提供最大的灵活性。
2、何时以及如何使用any?
声明any类型的情景,是当变量的类型未知或可以更改时使用,例如来自用户输入或外部源(API、库)的值。
但是请您记住,使用any过多可能会导致失去 TypeScript 类型检查的优势。它通常是一种临时解决方案,或在无法获得精确类型信息的情况下使用。
请来看以下例程:
let mystery : any = ' a surprise!' ;
// 重新分配给不同类型
mystery = 42 ; // 没有错误,现在是一个数字
mystery = false ; // 仍然没有错误,现在是一个布尔值
// 执行不同类型的典型操作
console.log ( mystery.toString ( ) ); // 用作布尔值
// 重新分配给一个对象
mystery = { key : 'value' } ;
console.log (mystery.key ) ; // 访问对象的属性,没有错误
解释
在此代码示例中,mystery首先是字符串,然后变为数字和布尔值,最后是对象。没有类型错误出现,这表明了 any的灵活性。它可以采用多种形式,并且仍允许其当前类型的典型操作。
2. unknown:安全且多功能的类型
TypeScript 中的类型unknown用于类型尚不清楚,但是需要确定的变量。
它是 any类型的安全对应项。虽然any允许您对变量执行任何操作,但是unknown限制性更强:您必须先通过类型检查并确认其类型,然后才能对其执行大多数操作。
何时以及如何使用unknown?
unknown是当您想要确保类型安全时,尤其是在处理来自外部来源(如 API 或用户输入)的值时,使用关键字就非常理想,因为这些值的类型事先并不清楚。这是告诉 TypeScript 在使用前需要检查类型,有助于避免在处理未知类型时可能发生的常见错误。
let ununcertainValue : unknown = 'Hello World' ; // 尝试直接
使用它将导致错误
// console.log(uncertainValue.toUpperCase()); // 错误
// 类型检查
if ( typeof uncertainValue === 'string' ) {
console.log ( uncertainValue.toUpperCase ());//安全并且有效!
}
解释
在这个例子中,uncertainValue最初设置为 unknown类型。TypeScript 会阻止诸如修改之类的操作,toUpperCase直到通过类型检查,确认类型为typeof uncertainValue === 'string'为止,这确保了变量操作的安全性。
附加unknown简单示例
在此示例中,我们将处理unknown可以是字符串或数字数组的类型:
let unknownValue : unknown =
[ "one" , 2 , "three" , 4 ];
// 直接将 unknownValue 用作数组将导致错误
// console.log(unknownValue.length); // 错误
// 检查数组的类型
if ( Array . isArray (unknownValue)) {
// 可以安全地用作数组
unknownValue. forEach ( item => {
if ( typeof item === " string" ) {
console.log ( `String: ${item} ` );
} else if ( typeof item === "number" ) {
console.log ( `Number: $ {item} ` ) ;
}
});
}
解释
解释
在这个例子中,unknownValue可以是数组,但 TypeScript 要求我们先验证其类型。我们用它Array.isArray()来检查它是否是一个数组,然后迭代其元素。
对于每个元素,我们在执行任何操作之前需要进一步检查它是字符串还是数字,这展示了如何使用unknown来确保复杂结构中的类型安全。
never:不可达状态的类型
never类型表示永远不会出现的值。它用于永远不会返回值的场景,比如在总是抛出错误的函数或无限循环中。
这是 TypeScript 理解和强制执行某些代码路径不会到达或不会产生值的一种方式。
何时以及如何使用never?
:never用在编写一个不期望返回值的函数时使用,或者在详尽的类型检查中,其中已涵盖所有可能的情况,并且返回值变得不可能。
以下是代码例子:
function throwError(message:string):never {
throw new Error(message);
}
throwError(“出错了”);//此函数不返回任何内容
解释
在此示例中,throwError函数被标记为never类型,因为它始终会抛出错误,
并且永远不会到达返回点。
我们来展示一个never的简单用例,表示无法正常完成的函数。
假设我们有一个代表不同种类宠物的联合类型和一个处理每种宠物的函数,下面将使用never来确保处理每种可能的宠物类型:
// 不同种类宠物的联合类型
type Pet = 'dog' | 'cat' | 'fish' ;
// 处理不同宠物类型的函数function
handlePet ( pet : Pet ) {
switch (pet) {
case 'dog' :
console.log ( " Handle a dog" ) ;
break ;
case 'cat' :
console.log( "Handle a cat" );
break ;
case 'fish' :
console.log( "Handle a fish ") ;
break;
default:
//确保处理所有可能的宠物类型
const exhaustiveCheck : never = pet;
return exhaustiveCheck;
}
}
handlePet ( 'dog' ) ; // 输出:“Handle a dog”
// handlePet('bird');
// TypeScript 抛出错误:类型“bird”不能分配给类型“Pet”。
解释
在此示例中,handlePet是一个接受特殊类型pet的函数。
该类型可以是'dog'、'cat'或'fish'。
代码案例default中的 never类型确保处理所有的情况。
如果您尝试传递不属于上述类型的Pet值,则 TypeScript 将产生编译时错误,从而阻止代码编译,这证明了 TypeScript 能够在开发过程的早期捕获此类错误。
何时使用这些类型:
-
any类型:当您逐渐从 JavaScript 转向 TypeScript 时或在类型安全不是优先考虑的复杂动态逻辑中使用。
-
unknown类型:在处理动态内容或第三方库时,数据类型不确定,因此可以使用更好的类型安全性。
-
never:在您想要确保函数不返回任何内容或进行详尽类型检查的情况下使用。
结语
理解any、unknown和never对于有效的 TypeScript 开发至关重要。
而any提供了很好的灵活性、unknown保证安全性,never确保某些条件不能实现。能够明智地使用它们,可以充分利用 TypeScript 类型系统的全部功能。
可以将这些类型整合到您的 TypeScript 项目中,将帮助您编写更强大且更易于维护的代码。而最关键的是平衡灵活性还有安全性。
祝您编码愉快!
作者:Jayanth babu (https://programwithjayanth.com/)
说明:一名高级前端工程师,拥有多年经验,专门从事前端 Web 技术。