TypeScript 3.x: 访问未知类型的属性

TypeScript 3.x: Access properties of type unknown

我从 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 方法的错误输入,但我仍然想解释一下,为什么我无法访问未知类型的属性。

总而言之,我的问题是:

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

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

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

由于您将 obj 明确定义为 any,因此调用 Object.entries returns

[string, unknown][]

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

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

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

回答您的问题:

Why can't I access properties of type unknown?

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

const value:any = el[1];

I guess there is a reason for the above question, but shouldn't the Object.entries return an array w/ element nr. 0 of type string and element nr. 1 of type any?

它实际上 returns [string, unknown][].

我认为,为了解决您的问题,重要的是提供有关 anyunknown 的一些背景信息。虽然您可以在 official TypeScript documentation 中找到详尽的比较列表,但我想我可以大胆地将文章缩短为几句话:any 基本上是一种放之四海而皆准的方法,因此 不是类型安全的。我所说的类型安全是指您可以访问不存在的 any 的运行时 属性。

unknown不一样。 unknown 在这方面与 any 相反。它通过声明 "I won't pretend I fit everything because I don't" 表示 any 的类型安全版本。因此 unknown 需要额外转换为所需的类型才能工作(因为它本身不具备任何属性)。

现在,进入实际问题。为什么 Object.entries 使用 unknown 而不是 any?因为说 "cast this unknown value to whatever you need before usage, I won't assume that I know anything about this type" 比 "I don't know what kind of type it is, but I'll assume that it has all possible properties of all possible types".

更安全

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

// 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)];
         
      }
    }