根据他们的 wiki,TypeScript 3.0 引入了 unknown
类型:
unknown 现在是保留类型名称,因为它现在是内置类型。根据您对 unknown 的预期用途,您可能希望完全删除声明(支持新引入的 unknown 类型),或将其重命名为其他名称。
unknown
和 any
有什么区别?我们什么时候应该使用 unknown
而不是 any
?
Anything is assignable to unknown, but unknown isn't assignable to anything but itself
听起来像押韵
您可以在 PR 或 RC announcement 中阅读有关 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 很有用。这迫使用户安全地自省返回值。
unknown 和 any 之间的区别描述为:
就像任何值一样,任何值都可以分配给未知数;但是,与任何不同的是,您不能访问类型未知的值的任何属性,也不能调用/构造它们。此外,类型 unknown 的值只能分配给 unknown 或 any。
要回答您何时应使用 unknown
而不是 any
的问题:
这对于想要表示“这可以是任何值,因此您必须在使用它之前执行某种类型的检查”的 API 很有用。这迫使用户安全地自省返回值。
查看 TypeScript 3.0 announcement,了解类型检查 unknown
类型变量的示例和更详细的说明。
unknown
的参数,这里的“你”是指我还是使用我函数的人?谁必须进行类型检查?
随便哪种:
any
类型代表所有可能的 JS 值。每种类型都可以分配给类型 any
。因此类型 any
是类型系统的通用超类型。 TS 编译器将允许对类型为 any
的值进行任何操作。例如:
let myVar: any;
myVar[0];
myVar();
myVar.length;
new myVar();
在许多情况下,这对 TS 编译器来说过于宽松了。即它将允许我们可能知道会导致运行时错误的操作。
未知类型:
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
找到好的示例。
我迟到了,但会尝试揭开它的神秘面纱。
const canBeAnything: any = 100;
const canNotBeAnything: unknown = 100;
// If we try to use a .startsWith() method
canBeAnything.startsWith('10'); // no error
canNotBeAnything.startsWith('10'); // Property 'startsWith' does not exist on type 'unknown'
在 unknown 上使用方法 .startsWith()
的唯一方法是显式告诉编译器类型,例如
(canNotBeAnything as string).startsWith('10'); // Chill down TS compiler, I know what I am doing.
后者不会显示任何编译错误,但它会在运行时引发错误,因为 canNotBeAnything
是数字类型,我们将其强制为 string
接受的答案是“未知哪个是任何类型安全的对应物”。
但是,正如此示例所示,unknown
是它自己的野兽,有时它的行为与 any
非常不同:
type Foo = unknown extends string ? true : false // false
type Bar = any extends string ? true : false // boolean - i.e. both true and false
any
类似于dynamic
,unknown
类似于object
。我喜欢unknown
,因为它更安全。虽然名字很混乱。unknown
和object
@nawfal 是否公平,尽管我想我看到你在逆变和协变方面得到了什么(例如,任何对象都可以分配给类型object
尽管对于unknown
可以分配任何对象或原语 - 类似地,unknown
可以分配给any
或它自己,而object
可以分配给dynamic
或它自己)。在旁注中,我不清楚为什么 TS 文档将unknown
称为顶级类型,因为它并不真正包含所有类型¯_(ツ)_/¯unknown
是我不知道;any
是 我不在乎unknown
是 我还不知道,因此我必须弄清楚,any
是 我不在乎,因此我不在乎unknown
,您的代码必须先识别一个类型,然后才能访问该类型的任何成员,否则 TS 编译器会报错;对于类型any
,编译器不会抱怨访问属性,即使该属性在运行时可能不存在?