typescript 如何进行类型检查以证明未知对象具有我需要它具有的所有嵌套键

cuxqih21  于 2023-02-05  发布在  TypeScript
关注(0)|答案(1)|浏览(131)

我试图确保对象具有我期望它具有的所有键(.result.items),唯一的问题是我得到以下错误:

Property result does not exist on type 'object'

日期:

typeof (object.result as Record<string, any>).items === "object"

我不理解这个错误,因为我似乎已经证明了object.result确实存在于我的前一行中,并且它应该是object类型。

let objectKeyCheck = (
  object: unknown
): object is { result: { items: object[] } } => {
  return (
    !!object &&
    typeof object === "object" &&
    !!(object as Record<string, any>).result &&
    typeof (object as Record<string, any>).result === "object" &&
    !!(object.result as Record<string, any>) &&
    typeof (object.result as Record<string, any>).items === "object"
  );
};
xoefb8l8

xoefb8l81#

这里的问题是,当你在表达式上使用类型Assert时,它会“屏蔽”表达式,使其不受通常可能发生的任何narrowing的影响。例如:

function foo(x: string | number) {

  if (typeof x === "string") {
    console.log(x.toUpperCase()); // okay
  }

  if (typeof (x as string) === "string") {
    console.log(x.toUpperCase()); // error!
  }

}

在第一个块中,我们对x执行typeof类型的保护,这允许我们将范围从string | number缩小到仅string;但是在第二个块中,我们没有保护x,而是保护x as string......这对x没有任何影响。
类型Assert和窄化不能真正混合使用。
为了解决这个问题,我会远离类型Assert,而只使用TypeScript 4.9中添加的支持,即使用in操作符对未列出的属性进行收缩:

let objectKeyCheck = (
    object: unknown
): object is { result: { items: object[] } } => {
    return (
        !!object &&
        typeof object === "object" &&
        "result" in object &&
        !!object.result &&
        typeof object.result === "object" &&
        "items" in object.result &&
        !!object.result.items &&
        typeof object.result.items === "object"
    );
};

一旦我们把objectunknown缩小到object,然后检查"result" in object,编译器会突然把object.result当作一个有效的索引,属性类型从unknown开始,然后我们可以把object.result缩小到object,对object.result.items做同样的处理。
请注意,上述内容依赖于TypeScript 4.9中添加的一个特性。如果您使用的是早期版本,几乎可以肯定还有其他方法也可以解决这个问题,但我不打算在这里离题探讨它们,因为它们已经过时,并且随着时间的推移将变得不那么有用。推荐的做法是升级TypeScript,对于那些需要针对特定旧版本的代码的人,我可能想问一个关于语言版本控制的新问题。
Playground代码链接

相关问题