有关 typescript 中 unknown 类型的理解
当在 TypeScript (TS) 中使用 unknown
类型时,它表示一个类型未知的值。与 any
类型不同,unknown
类型更加类型安全,因为它要求在使用之前进行类型检查或类型断言。
下面是一些关于 unknown 类型的详细解释:
-
任何值都可以被赋值为
unknown
: 你可以将任何值赋给unknown
类型的变量,就像你可以将任何值赋给any
类型的变量一样。let myVar: unknown = 10; myVar = 'Hello'; myVar = [1, 2, 3];
-
不能直接操作
unknown
类型的值: 与any
类型不同,你不能直接对unknown
类型的值进行操作或调用其方法。let myVar: unknown = 10; // Error: Object is of type 'unknown'. // myVar.toFixed();
-
需要类型检查或类型断言: 在使用
unknown
类型的值之前,你需要进行类型检查或使用类型断言明确告诉 TypeScript 该值的类型。let myVar: unknown = 10; if (typeof myVar === 'number') { let myNumber: number = myVar; // 类型检查通过 console.log(myNumber.toFixed(2)); }
或者使用类型断言:
let myVar: unknown = 10; let myNumber: number = myVar as number; // 使用类型断言 console.log(myNumber.toFixed(2));
-
类型守卫: 使用类型守卫可以帮助你在特定条件下缩小
unknown
类型的范围。function processValue(value: unknown) { if (typeof value === 'string') { // 在这个分支中,value 被认定为 string 类型 console.log(value.toUpperCase()); } else if (Array.isArray(value)) { // 在这个分支中,value 被认定为数组类型 console.log(value.length); } }
总体来说,unknown
类型提供了更严格的类型检查,鼓励开发者在使用未知类型的值时进行明确的类型处理,以减少潜在的运行时错误。
我应该在什么时候使用 unknown 类型呢
unknown
类型通常用于以下情况:
-
动态数据: 当你处理来自动态来源(例如用户输入、动态 API 响应等)的数据时,你可能无法确定数据的确切类型。使用
unknown
类型允许你在使用数据之前进行类型检查,从而提高类型安全性。function processData(data: unknown) { if (typeof data === 'string') { // 处理字符串类型 console.log(data.toUpperCase()); } else if (Array.isArray(data)) { // 处理数组类型 console.log(data.length); } else { // 其他情况,可以根据具体需求进行处理 } }
-
动态类型转换: 当你需要进行动态类型转换,但在转换之前无法确定确切的类型时,
unknown
类型可以作为一个临时的容器,以便在类型检查后执行转换。let userInput: unknown = getUserInput(); // 从某处获取用户输入 if (typeof userInput === 'string') { let userInputString: string = userInput; // 类型检查通过,进行转换 console.log(userInputString.toUpperCase()); }
-
与泛型结合使用: 在 TypeScript 中,你可能编写一些泛型代码,这些代码需要在某些地方使用特定类型的值,但你在编写代码时无法确定这些类型是什么。在这种情况下,你可以使用
unknown
类型作为泛型参数,以表示这些类型是未知的。考虑下面的例子:
function processValue<T>(value: unknown): T { // 进行类型检查和转换,然后返回特定类型 return value as T; }
在这个例子中,
processValue
函数是一个泛型函数,它接受一个unknown
类型的参数value
,然后尝试将其转换为泛型类型T
。这允许你调用该函数并为T
提供一个具体的类型参数,例如:let stringValue: string = processValue<string>('Hello'); let numberValue: number = processValue<number>(42);
在第一次调用中,
processValue<string>('Hello')
将返回一个字符串,而在第二次调用中,processValue<number>(42)
将返回一个数字。这样,你可以在调用函数时指定所需的类型,而函数本身能够在运行时进行相应的类型检查和转换。这种使用
unknown
类型的方式通常在你编写泛型代码时,对类型的确切细节不清楚或者不重要的情况下很有用。在这种情况下,泛型函数可以接受不同类型的参数,并且用户可以在调用时提供所需的具体类型。 -
在 TypeScript 中对旧代码进行迁移: 如果你正在将 JavaScript 代码迁移到 TypeScript,并且无法确定变量的确切类型,可以使用
unknown
类型作为临时解决方案,以后再逐步添加更精确的类型信息。
总体来说,使用 unknown
类型的关键点是确保在使用该值之前进行适当的类型检查或类型断言。这有助于提高代码的可读性和类型安全性,减少潜在的运行时错误。
unknown类型 和 any 类型的区别是什么
unknown
类型和 any
类型在 TypeScript 中都用于处理不确定或动态类型的情况,但它们之间有一些重要的区别:
-
类型安全性:
any
类型:使用any
类型时,TypeScript 不会提供任何类型检查或提示,允许你对变量进行任何操作,而无需先进行类型检查。这可能导致潜在的运行时错误,因为编译器无法捕获所有类型不匹配的问题。unknown
类型:使用unknown
类型时,TypeScript 要求在使用值之前进行类型检查或类型断言。这增加了类型安全性,因为你必须显式地处理未知类型的值,而不是随意进行操作。
-
类型断言:
-
any
类型:不需要进行类型断言,可以直接对any
类型的值进行任何操作。 -
unknown
类型:在使用unknown
类型的值之前,必须进行类型检查或使用类型断言,以告诉 TypeScript 该值的确切类型。let myAny: any = 10; let myUnknown: unknown = 10;
let anyValue: string = myAny; // No error, implicit any // Error: Type 'unknown' is not assignable to type 'string'. let unknownValue: string = myUnknown as string; // Type assertion or additional check is needed
-
-
类型推导:
-
any
类型:any
类型的变量会导致 TypeScript 放弃对该变量的类型推导,因为该变量可以是任何类型。 -
unknown
类型:使用unknown
类型时,TypeScript 仍然可以对变量进行类型推导,但在使用变量之前,你需要明确告诉 TypeScript 具体的类型。let myAny: any = 'Hello'; let myUnknown: unknown = 'Hello';
let inferredAny = myAny.length; // No error, inferred as any let inferredUnknown = myUnknown.length; // Error: Object is of type 'unknown'
// After type assertion or type check if (typeof myUnknown === 'string') { let length: number = myUnknown.length; // Type check allows access }
-
-
向下兼容性:
-
any
类型:any
类型允许向下兼容,即你可以将any
类型的值分配给任何其他类型。 -
unknown
类型:与any
不同,unknown
类型不是向下兼容的,除非进行类型检查或类型断言。let myAny: any = 'Hello'; let myUnknown: unknown = 'Hello';
let stringVar: string = myAny; // No error, any is assignable to all types // Error: Type 'unknown' is not assignable to type 'string'. let stringVar2: string = myUnknown; // Error without type assertion or type check
-
总的来说,unknown
类型相对于 any
类型提供了更严格的类型检查,鼓励开发者在使用不确定类型的值时进行明确的类型处理,以提高代码的可读性和类型安全性。
再解释一下 unknown 类型不是向下兼容的是什么意思?
当说 "unknown 类型不是向下兼容的" 时,指的是在 TypeScript 中,不能直接将 unknown
类型的值分配给其他具体的类型,而不进行类型检查或类型断言。这是 TypeScript 中的一种保守性措施,以确保更严格的类型安全性。
考虑以下例子:
let myUnknown: unknown = 'Hello';
let stringVar: string = myUnknown; // Error: Type 'unknown' is not assignable to type 'string'.
在这个例子中,尽管 myUnknown
的实际值是字符串 'Hello'
,但 TypeScript 不允许直接将 myUnknown
分配给 string
类型的变量,因为 unknown
类型不是向下兼容的。
为了解决这个问题,你需要进行类型检查或类型断言:
-
类型检查:
if (typeof myUnknown === 'string') { let stringVar: string = myUnknown; // Type check allows access }
-
类型断言:
let stringVar: string = myUnknown as string; // Type assertion allows access
在这两种情况下,你在使用 myUnknown
的值之前明确告诉 TypeScript 它的确切类型是字符串,从而避免了类型错误。这种要求进行类型检查或类型断言的方式增加了代码的类型安全性,因为开发者需要更加明确地处理不确定类型的值。
总结一下: TypeScript 允许将 unknown
类型的值分配给任何其他类型,因为 unknown
类型是 TypeScript 类型系统中的顶级类型,可以容纳任何值。
不向下兼容的意思是:经过类型检查或类型断言,你可以将 unknown
类型复制给任何其他类型;但是你不能再没有经过类型检查或类型断言就去分配这是不行的。
转载自:https://juejin.cn/post/7322518831939567625