【问题标题】:Narrowing an object of type unknown缩小未知类型的对象
【发布时间】:2021-11-19 01:53:36
【问题描述】:

我已经阅读了关于缩小 TypeScript 中 unknown 类型的 object 的多个帖子和问题。但我还没有找到这个具体的问题或解决方案。

我发现大多数解决方案都可以做这样的事情。

const result: unknown = {
  movieName: "test",
};

if (
  typeof result === "object" &&
  result !== null &&
  "movieName" in result &&
  typeof result.movieName === "string" // <-- Error Here
) {}

错误状态

“对象”类型上不存在属性“movieName”

如何缩小范围以使其知道unknown 是一个包含movieName 属性的object?如何访问 result.movieName 以获取 unknown 类型?

编辑:perhaps it's not possible? 以及下面 cmets 中将其声明为 Record 的建议可能是GitHub request的唯一方法?

【问题讨论】:

  • 也许你可以使用result: Record&lt;string, unknown&gt;
  • 上面的类型只是为了测试。未知结果实际上来自 API。

标签: typescript


【解决方案1】:

这是目前 TypeScript 中缺少的功能。有关相关功能请求,请参阅 microsoft/TypeScript#21732。现在,当您像 k in result 一样使用 in operator as a type guard 时,只有当 result 的类型是 union 时,它才会真正进行有意义的缩小,其中已知某些成员拥有密钥 k 而其他成员没有。它不断言键为k 的属性的存在。所以在你的情况下,result 的类型只是object(从unknown 缩小),没有任何有意义的事情发生。

我有时使用的解决方法是编写自己的user-defined type guard function,它的行为方式与我希望in 的行为方式相同。例如:

function hasKey<K extends string, T extends object>(
    k: K, o: T
): o is T & Record<K, unknown> {
    return k in o;
}

现在,我不写k in result,而是写hasKey(k, result)

if (
    typeof result === "object" &&
    result !== null &&
    hasKey("movieName", result) &&
    typeof result.movieName === "string" // okay
) {
    result.movieName.toUpperCase(); // okay
}

这可以按您的意愿工作,并且可以说是您可以在这里获得的最接近类型安全性的方法,至少在采取措施以本机解决 microsoft/TypeScript#21732 之前是这样。

Playground link to code

【讨论】:

  • 这对我来说效果很好。有没有办法将前三个步骤组合成另一个类型检查功能?诸如isObjectWithKey 之类的函数检查它是否为空并且是一个对象然后运行hasKey?感谢您的帮助。
  • 当然可以this。如果您需要进一步了解,可以考虑发布新问题,因为以前答案的评论部分并不总是获得后续答案的最佳位置。
猜你喜欢
  • 2022-01-21
  • 2021-11-16
  • 2022-01-25
  • 2021-07-13
  • 2016-06-29
  • 2021-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多