【发布时间】:2018-12-28 14:33:27
【问题描述】:
TypeScript 3.0 引入了 unknown 类型,根据他们的 wiki:
unknown 现在是保留类型名称,因为它现在是内置类型。 根据您对 unknown 的预期用途,您可能希望删除 完全声明(支持新引入的未知类型),或 将其重命名为其他名称。
unknown 和 any 有什么区别?我们什么时候应该使用unknown 而不是any?
【问题讨论】:
TypeScript 3.0 引入了 unknown 类型,根据他们的 wiki:
unknown 现在是保留类型名称,因为它现在是内置类型。 根据您对 unknown 的预期用途,您可能希望删除 完全声明(支持新引入的未知类型),或 将其重命名为其他名称。
unknown 和 any 有什么区别?我们什么时候应该使用unknown 而不是any?
【问题讨论】:
您可以在PR 或RC announcement 中阅读有关unknown 的更多信息,但其要点是:
[..] unknown 哪个是 any 的类型安全对应物。任何东西都可以分配给未知,但未知不能分配给除了它本身和任何没有类型断言或基于控制流的收缩的东西。同样,在未先断言或缩小到更具体的类型之前,不允许对未知数进行任何操作。
几个例子:
let vAny: any = 10; // We can assign anything to any
let vUnknown: unknown = 10; // We can assign anything to unknown just like any
let s1: string = vAny; // Any is assignable to anything
let s2: string = vUnknown; // Invalid; we can't assign vUnknown to any other type (without an explicit assertion)
vAny.method(); // Ok; anything goes with any
vUnknown.method(); // Not ok; we don't know anything about this variable
建议的用法是:
我们经常想在 TypeScript 中描述能力最低的类型。这对于想要表示“这可以是任何值,因此您必须在使用它之前执行某种类型的检查”的 API 很有用。这迫使用户安全地自省返回值。
【讨论】:
any 就像 dynamic 和 unknown 就像 object。我喜欢unknown,因为它更安全。不过名字很混乱。
unknown 和 object @nawfal 是否公平,尽管我想我看到你在逆变和协方差方面得到了什么(例如任何object 可分配给类型 object 尽管对于 unknown 可以分配任何对象或原语 - 类似地,unknown 可以分配给 any 或它自己,object 可以分配给 dynamic 或它自己)。在旁注中,我不清楚为什么 TS 文档将 unknown 称为顶级类型,因为它并不真正包含所有类型¯_(ツ)_/¯
unknown是我不知道; any 是 我不在乎
unknown 是 我还不知道,因此我必须弄清楚,any 是 我不知道关心,所以我不在乎
unknown 和 any 的区别描述为:
很像
any,任何值都可以分配给unknown;但是,与any不同,您不能访问类型为unknown的值的任何属性,也不能调用/构造它们。此外,unknown类型的值只能分配给unknown或any。
要回答您何时应该使用unknown 而不是any:
这对于想要表示“这可以是任何值,所以 您必须在使用之前执行某种类型的检查”。这迫使 用户可以安全地自省返回值。
查看TypeScript 3.0 announcement 以获取类型检查unknown 类型变量的示例以及更详细的说明。
【讨论】:
unknown 类型的参数,这里的“你”是指我还是那些使用我的函数的人?谁必须做类型检查?
any 类型:any 类型代表所有可能的 JS 值。每个类型都可以分配给类型any。因此,any 类型是类型系统的通用超类型。 TS 编译器将允许对类型为 any 的值进行任何操作。例如:
let myVar: any;
myVar[0];
myVar();
myVar.length;
new myVar();
在许多情况下,这对 TS 编译器过于宽松。即它将允许我们可能知道会导致运行时错误的操作。
unknown 类型:unknown 类型代表(就像any)所有可能的 JS 值。每种类型都可以分配给类型unknown。因此unknown 类型是类型系统的另一个通用超类型(与any 并列)。但是,TS 编译器不会允许对键入的 unknown 值进行任何操作。此外,unknown 类型只能分配给any 类型。一个例子将阐明这一点:
let myVar: unknown;
let myVar1: unknown = myVar; // No error
let myVar2: any = myVar; // No error
let myVar3: boolean = myVar; // Type 'unknown' is not assignable to type 'boolean'
// The following operations on myVar all give the error:
// Object is of type 'unknown'
myVar[0];
myVar();
myVar.length;
new myVar();
【讨论】:
任何,未知:
任何:
未知:
const a: any = 'a'; // OK
const b: unknown = 'b' // OK
const v1: string = a; // OK
const v2: string = b; // ERROR
const v3: string = b as string; // OK
a.trim() // OK
b.trim() // ERROR
【讨论】:
doesn't allow to call any method,这是不正确的(或者可能只是难以理解?)。无论如何,您可以对键入为 any 的值调用任何方法。
as T的唯一答案,这会将类型从unknown更改为T。非常好。
any 基本上是在使用纯 JavaScript。 unknown 基本上是一种更安全的方式来处理你不知道类型的东西。
它们在语义上是不同的。
unknown 是所有其他类型的父类型。它是类型系统中的常规类型。
any 表示“关闭类型检查”。这是一种元编程。
【讨论】:
any?
如果您编写的函数仅将输入传递给另一个函数,请使用unknown。从功能上看:“我不知道,我不想知道”。使用unknown没有任何问题。
例如:
function buy(item: unknown): Purchase {
if (item) {
return purchase(item);
} else {
throw new TypeError('item is missing');
}
}
如果您需要调用该值的属性,那么any 更适合。
Linting 可能不喜欢any,建议您输入更具体的内容。这样,如果您将接口从 isItem 更改为 isValid,typescript 会告诉您更新代码。
例如:
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
function isItem(item: any): item is Purchase {
return !!item?.price;
}
function isStuff(item: unknown): item is Stuff {
return (item as Stuff).it !== undefined;
}
function isStuff(item: any): item is Stuff {
return item.it !== undefined;
}
camelcaseKeys(item) as unknown as Item;
如果您有兴趣,请参阅user defined guards,我带来了它,因为这是我需要的少数情况之一。
来自ultimatecourses的这篇博客:
没有其他选项时使用
any类型
很难找到any 的好例子。
【讨论】: