【发布时间】:2021-11-10 16:57:22
【问题描述】:
是否可以创建一个 TypeScript 类型保护函数来确定给定键是否在给定(通用)对象中 - 非常类似于 key in obj,但作为功能类型保护(与此问题无关的原因需要) .
例如,像这样的:
export function has<T extends { [index: string]: any; [index: number]: any }>(
obj: T,
property: string | symbol | number
): property is keyof T {
return Object.prototype.hasOwnProperty.call(obj, property)
}
// Then in user land somewhere:
interface Foo {
bar: string
}
interface Fuzz {
buzz: string
}
function doWork(thing: Foo | Fuzz) {
if (has(thing, 'bar')) {
alert(thing.bar) // ideally we've type narrowed to know thing contains foo
}
}
上面的代码不能像我预期的那样工作 (alert(thing.foo)) 不知道 foo 存在 - 显然我的类型保护声明 property is keyof T 没有达到我的预期。
您可以输入 guard 结果仅为 Foo 或 Fuzz - 但我特别想输入 guard 某个特定键存在于泛型上。
【问题讨论】:
-
this 是否满足您的需求?您的类型保护功能正在缩小
property,但您已经确切知道"bar"是什么。您的用例似乎是您想缩小obj的范围。我的链接中的has版本仅在obj是联合类型时才有效。如果这适用于您的用例,我会写一个答案。如果没有,请修改问题以详细说明您的用例,我会看看它。让我知道任何一种方式,祝你好运。 -
这是一个聪明的解决方案。我真的希望 obj in 成为任何类型的对象,而不仅仅是联合。不过,这似乎非常接近。
-
如果您有 minimal reproducible example 的内容不适用于我的解决方案,我可能会更新解决方案。如果没有示例,就很难预测您真正关心的用例。
-
Here's an example 的不良影响,
obj缩小为never -
你为什么要对带有字符串索引签名的东西进行任何缩小,你希望它缩小到什么?看来您应该像
x.buzz ??= 123一样直接访问x.buzz。不管怎样,用你的用例试试this version,让我知道;我已经放弃了明确缩小联合,而是使用了交叉点。请记住将您关心的任何用例添加到问题本身,以便答案不依赖于 cmets 的状态。
标签: typescript typescript-generics