当使用
checkVisibility
检查最近添加的方法 in
是否存在时,TypeScript 会生成错误:
function isElementVisible(element: Element) {
return ('checkVisibility' in element) ? element.checkVisibility() : element.getClientRects().length > 0;
}
错误:
(2339) Property 'getClientRects' does not exist on type 'never'.
我重写如下
function isElementVisible(element: Element) {
return element.checkVisibility ? element.checkVisibility() : element.getClientRects().length > 0;
}
这个表示法没有错误,而且它大致是一样的,所以我就这样决定了。
我理解为什么它说
never
,因为从 TS 角度来看,lib.dom.d.ts
定义了 checkVisibility
,所以它总是存在,尽管实际上在较旧的浏览器中它不存在。
但我仍然很好奇,有没有办法让第一个变体与
in
正常工作?
您遇到了 microsoft/TypeScript#51059 中报告的问题。 TypeScript 4.9 引入了 使用
in
运算符 缩小未列出的属性,如 microsoft/TypeScript#50666 中实现的那样。如果您选中 if ("someKey" in someObj) {⋯} else {⋯}
,TypeScript 将使用该检查来缩小 someObj
的类型。因此,如果检查为 true,则 someObj
会缩小为包含 someKey
的类型,如果检查为 false,则可能会缩小为包含 someKey
的 not类型。 这正在按预期工作。
但是checkVisibility()
方法的
Element
s的TypeScript类型的编写使得该方法始终存在:
interface Element {
checkVisibility(options?: CheckVisibilityOptions): boolean;
}
不认为是可选;它不是
这样声明的:interface Element {
checkVisibility?(options?: CheckVisibilityOptions): boolean;
// ^ nope
}
因此,当您检查
if ("checkVisibility" in element)
时,TypeScript 会认为始终是
true
。因此,
else
子句最终将
element
一直缩小到不可能的never
类型。 这是不幸的,因为它与您正在进行的功能测试相互作用很差。尽管如此,他们还是这样保留它,因为否则即使在功能测试之后,您也非常需要使用 可选链来编写
element.checkVisibility?.()
(因为可能 checkVisibility
是 present 但 undefined
,除非您已经启用了--exactOptionalPropertyTypes
,它甚至具有更多深远的影响)。
这很不幸,但行为符合预期。 你需要解决它。
最小的修复方法是使用类型断言等来破坏有问题的缩小范围:
function isElementVisible(element: Element) {
return ("checkVisibility" as string in element) ?
element.checkVisibility() : element.getClientRects().length > 0;
}
或者您可以直接read属性而不是使用
in
检查,以避免缩小范围:
function isElementVisible(element: Element) {
return element.checkVisibility ?
element.checkVisibility() : element.getClientRects().length > 0;
}
或者您可以使用可选链接和无效合并来使用即使
checkVisibility
被认为是可选的也可以工作的形式:
function isElementVisible(element: Element) {
return element.checkVisibility?.() ?? (element.getClientRects().length > 0);
}
或者您可以采取任何其他解决方法。