【问题标题】:'unknown' vs. 'any'“未知”与“任何”
【发布时间】:2018-12-28 14:33:27
【问题描述】:

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

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

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

【问题讨论】:

    标签: typescript typescript3.0


    【解决方案1】:

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

    【讨论】:

    • 任何来自 C# 背景的人,any 就像 dynamicunknown 就像 object。我喜欢unknown,因为它更安全。不过名字很混乱。
    • 我不知道比较 unknownobject @nawfal 是否公平,尽管我想我看到你在逆变和协方差方面得到了什么(例如任何object 可分配给类型 object 尽管对于 unknown 可以分配任何对象或原语 - 类似地,unknown 可以分配给 any 或它自己,object 可以分配给 dynamic 或它自己)。在旁注中,我不清楚为什么 TS 文档将 unknown 称为顶级类型,因为它并不真正包含所有类型¯_(ツ)_/¯
    • 我是怎么读的:unknown我不知道any我不在乎
    • 更详细地说,unknown我还不知道,因此我必须弄清楚any我不知道关心,所以我不在乎
    【解决方案2】:

    unknown 和 any 的区别描述为:

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

    要回答您何时应该使用unknown 而不是any

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

    查看TypeScript 3.0 announcement 以获取类型检查unknown 类型变量的示例以及更详细的说明。

    【讨论】:

    • “这可以是任何值,因此在使用它之前必须执行某种类型的检查”。假设我正在编写一个可重用函数,它接受unknown 类型的参数,这里的“你”是指我还是那些使用我的函数的人?谁必须做类型检查?
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      任何,未知:

      • 允许分配任何类型

      任何:

      • 允许分配给任何类型
      • 允许调用任何方法

      未知:

      • 不允许分配给任何类型
      • 不允许调用任何方法
      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 基本上是一种更安全的方式来处理你不知道类型的东西。
      【解决方案5】:

      它们在语义上是不同的。

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

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

      【讨论】:

      • 这些简单的句子很有意义。
      • 您能详细说明“元编程”吗?你为什么用它来联系any
      • @Andru “元编程”的意思是“任何”这个词不是正在编译的内容,也就是说,它没有告诉编译器要编译什么。相反,它配置了编译的过程,也就是说,它告诉编译器如何编译。
      【解决方案6】:

      未知

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-20
        • 2013-04-14
        • 2016-06-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多