【问题标题】:TypeScript 3.x: Access properties of type unknownTypeScript 3.x:访问未知类型的属性
【发布时间】:2020-05-07 09:07:46
【问题描述】:

我从 TypeScript 文档中了解到,您无法访问未知类型的属性:

// No property accesses, element accesses, or function calls

function f11(x: unknown) {
    x.foo;  // Error
    x[5];  // Error
    x();  // Error
    new x();  // Error
}

但我不明白为什么?如果我可以分配包括对象在内的每个值,为什么我不能访问属性?

我正在应对以下情况:我有一个 any 类型的对象,我将它传递给 Object.entries 方法,然后调用 forEach

因为它是any 类型,所以forEach 调用参数将是一个数组,其中第一个元素为字符串类型,第二个元素为未知类型。

在我的例子中,第二个元素是一个对象,但如果不转换它的类型,我就无法访问它的属性,这似乎是错误的做法。

这是一个示例,它会引发 TS 错误(只是一个抽象,我知道在这种情况下将其声明为 any 没有意义):

const obj: any = {
  val1: "someval",
  val2: {
    some: "some",
    object: "object",
  },
};
Object.entries(obj).forEach(el => {
  if (el[1].some) {
    console.log(el);
  }
});

我猜这也可能是 Object.entries 方法的错误类型,但我仍然想解释一下,为什么我不能访问类型为 unknown 的属性。

总结一下,我的问题是:

  1. 为什么即使未知类型可以是对象,我也无法访问未知类型的属性?
  2. 我想上述问题是有原因的,但Object.entries 不应该返回一个带有元素 nr 的数组。 0 类型的字符串和元素 nr。任何类型的 1 个?

【问题讨论】:

    标签: typescript typescript-typings typescript3.0


    【解决方案1】:

    我认为,为了解决您的问题,重要的是要提供一些关于 anyunknown 的背景信息。虽然您可以在 official TypeScript documentation 中找到详尽的比较列表,但我想我可以冒昧地将文章缩短为几句话:any 基本上是一种万能的,因此 不是类型安全。类型安全是指您可以访问不存在的 any 的运行时属性。

    unknown 不同。在这方面unknownany 正好相反。它表示any 的类型安全版本,声明“我不会假装我适合所有东西,因为我不适合”。所以unknown 需要额外转换为所需的类型才能工作(因为它本身不具备任何属性)。

    现在,进入实际问题。为什么Object.entries 使用unknown 而不是any?因为说“在使用前将这个未知值转换为你需要的任何值,我不会假设我对这种类型一无所知”比“我不知道它是哪种类型”更安全是,但我会假设它具有所有可能类型的所有可能属性”。

    【讨论】:

    • 哦,所以unknown 类型实际上是要“重新分配”给具有可访问属性的类型?所以提醒开发者,在做诸如访问属性之类的事情时,他必须确保它存在,这样他就不会犯可能导致运行时错误的错误。虽然使用 any 类型,但他可以这样做,这可能是错误的,因此不是类型安全的。
    【解决方案2】:

    我也有同样的问题 但我尝试这种技术来解决它

    // choice is a custom data type 
    export interface Choice {
      id: string; 
      isSelected: boolean; 
      score: number;
      status: string; 
    }
    for (const [key, value] of Object.entries(this.tableForm.value)) {
          if (value) {
            let choiceItem  = value as Choice;
            let choiceIds = [String(choiceItem.id)];
             
          }
        }
    

    【讨论】:

      【解决方案3】:

      Object.entries(...)(取自GitHub)的定义是:

      entries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][];
      

      由于您将obj 明确定义为any,因此对Object.entries 的调用返回

      [string, unknown][]
      

      您可以在声明 obj 时简单地删除 : any,TypeScript 将根据定义推断其类型。

      在这种情况下,对Object.entries 的调用将返回:

      [string, string | { some: string; object string; }][]
      

      回答您的问题:

      为什么我不能访问未知类型的属性?

      编译器试图通过在编译时检查来避免运行时错误。如果您真的知道自己在做什么,您可以随时将unknown 转换为any。例如:

      const value:any = el[1];
      

      我想上述问题是有原因的,但 Object.entries 不应该返回一个带有元素 nr 的数组。 0 类型的字符串和元素 nr。任何类型的 1 个?

      它实际上返回[string, unknown][]

      【讨论】:

      • 我明白,在我的示例中,将其声明为 any 没有任何意义。这只是一个抽象。即当对象来自获取时,它将是任何类型...
      • 我为我的问题添加了摘要。 (我确实知道我的问题有很多解决方法我只是不知道它为什么存在)
      • 感谢您更新的答案,但他们都只是说“是这样”和“它发生了”,但我实际上问为什么是这样,为什么返回类型未知,即使从我的角度来看,any 会更精确
      猜你喜欢
      • 2011-06-16
      • 2021-12-10
      • 1970-01-01
      • 1970-01-01
      • 2017-08-31
      • 2019-03-07
      • 2022-01-22
      • 2019-02-07
      • 2016-08-21
      相关资源
      最近更新 更多