缩小未知类型的对象

Die*_*sel 16 typescript

我在这里阅读了多篇关于缩小TypeScriptobject类型的帖子和问题。unknown但我还没有找到这个具体的问题或解决方案。

我发现大多数解决方案都需要执行类似的操作。

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

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

错误指出

属性“movieName”在类型“object”上不存在

我如何缩小范围,以便它知道该unknown事物是object包含该属性的movieName?如何访问result.movieName类型unknown

编辑:也许这是不可能的?下面评论中的建议将其声明为 Record<string,unknown> 可能是每个GitHub 请求的唯一方法?

jca*_*alz 20

TS4.9+ 更新

TypeScript 4.9 将引入对in未列出属性的运算符缩小的支持,如microsoft/TypeScript#50666中实现的那样,作为对下面提到的microsoft/TypeScript#21732的修复。此时,上面的代码无需修改即可运行:

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

if (
    typeof result === "object" &&
    result !== null &&
    "movieName" in result &&
    typeof result.movieName === "string" // <-- okay
) {
    result.movieName.toUpperCase(); // <-- okay
}
Run Code Online (Sandbox Code Playgroud)

Playground 代码链接


TS4.8 的先前答案-

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

我有时使用的解决方法是编写自己的用户定义类型保护函数in,该函数的行为方式符合我想要的行为方式。例如:

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

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

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

这可以按照你想要的方式工作,并且可以说是你在这里可以得到的最接近类型安全的方式,至少在本地解决 microsoft/TypeScript#21732 之前是这样。

Playground 代码链接

  • 当然,你可以做到[这个](https://tsplay.dev/mbGb3W)。如果您需要进一步的信息,您可以考虑发布新问题,因为以前答案的评论部分并不总是获得后续答案的最佳位置。 (3认同)