TypeScript 对新添加方法的检查以错误“属性...在类型‘从不’上不存在。”

问题描述 投票:0回答:1

当使用

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
正常工作?

typescript
1个回答
0
投票

您遇到了 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);
}

或者您可以采取任何其他解决方法。

Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.