ChatGPT解决这个技术问题 Extra ChatGPT

“未知”与“任何”

根据他们的 wiki,TypeScript 3.0 引入了 unknown 类型:

unknown 现在是保留类型名称,因为它现在是内置类型。根据您对 unknown 的预期用途,您可能希望完全删除声明(支持新引入的 unknown 类型),或将其重命名为其他名称。

unknownany 有什么区别?我们什么时候应该使用 unknown 而不是 any

Anything is assignable to unknown, but unknown isn't assignable to anything but itself 听起来像押韵

I
Ilya

您可以在 PRRC 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 很有用。这迫使用户安全地自省返回值。


任何来自 C# 背景的人,any 类似于 dynamicunknown 类似于 object。我喜欢 unknown,因为它更安全。虽然名字很混乱。
我不知道比较 unknownobject @nawfal 是否公平,尽管我想我看到你在逆变和协变方面得到了什么(例如,任何对象都可以分配给类型 object尽管对于 unknown 可以分配任何对象或原语 - 类似地,unknown 可以分配给 any 或它自己,而 object 可以分配给 dynamic 或它自己)。在旁注中,我不清楚为什么 TS 文档将 unknown 称为顶级类型,因为它并不真正包含所有类型¯_(ツ)_/¯
我是怎么读的:unknown我不知道any我不在乎
更详细地说,unknown我还不知道,因此我必须弄清楚any我不在乎,因此我不在乎
因此,对于类型 unknown,您的代码必须先识别一个类型,然后才能访问该类型的任何成员,否则 TS 编译器会报错;对于类型 any,编译器不会抱怨访问属性,即使该属性在运行时可能不存在?
A
Awad Maharoof

unknown 和 any 之间的区别描述为:

就像任何值一样,任何值都可以分配给未知数;但是,与任何不同的是,您不能访问类型未知的值的任何属性,也不能调用/构造它们。此外,类型 unknown 的值只能分配给 unknown 或 any。

要回答您何时应使用 unknown 而不是 any 的问题:

这对于想要表示“这可以是任何值,因此您必须在使用它之前执行某种类型的检查”的 API 很有用。这迫使用户安全地自省返回值。

查看 TypeScript 3.0 announcement,了解类型检查 unknown 类型变量的示例和更详细的说明。


“这可以是任何值,因此您必须在使用它之前执行某种类型的检查”。假设我正在编写一个可重用函数,它接受类型为 unknown 的参数,这里的“你”是指我还是使用我函数的人?谁必须进行类型检查?
W
Willem van der Veen

随便哪种:

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();

b
bubbleking

任何,未知:

允许分配任何类型

任何:

允许分配给任何类型

允许调用任何方法

未知:

不允许分配给任何类型

不允许调用任何方法

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 基本上是一种更安全的方式来处理您不知道类型的内容。
Z
Zim

它们在语义上是不同的。

unknown 是所有其他类型的父类型。它是类型系统中的常规类型。

any 表示“关闭类型检查”。这是一种元编程。


这些简单的句子很有意义。
您能否详细说明“元编程”?您为什么在 any 中使用它?
@Andru“元编程”意味着“任何”这个词不是正在编译的内容,也就是说,它没有告诉编译器要编译什么。相反,它配置了编译的过程,也就是说,它告诉编译器如何编译。
e
ecoologic

未知

如果您编写的函数仅将输入传递给另一个函数,请使用 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 找到好的示例。


S
Shankar Regmi

我迟到了,但会尝试揭开它的神秘面纱。

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


T
TrevTheDev

接受的答案是“未知哪个是任何类型安全的对应物”。

但是,正如此示例所示,unknown 是它自己的野兽,有时它的行为与 any 非常不同:

type Foo = unknown extends string ? true : false // false
type Bar = any extends string ? true : false     // boolean - i.e. both true and false

这个答案似乎更像是对已接受答案的评论——而不是实际答案。
@CodeFinity 两者兼而有之-问题是“未知和任何之间有什么区别?”我的回答提供了一个值得理解的关键而重要的区别。