简体   繁体   English

使用 @ts-check 在 JS 文件中键入断言元素

[英]Type assert an element in a JS file with @ts-check

I have a JS file with a // @ts-check directive, using JSDoc comments to denote types.我有一个带有// @ts-check指令的 JS 文件,使用 JSDoc 注释来表示类型。

The problem is that the elements fail type checks when retrieved from the document .问题是从document中检索元素时类型检查失败。

So we have in HTML:所以我们在 HTML 中有:

<input id="myInput">...

When I get this element in JS the type checking throws an error:当我在 JS 中获取此元素时,类型检查会引发错误:

// @ts-check
const myInput = document.getElementById('myInput');
myInput.value = 'foobar';

Property 'value' does not exist on type 'HTMLElement' “HTMLElement”类型上不存在属性“值”

If I specify the expected type with a JSDoc @type comment then that also fires an error:如果我使用 JSDoc @type注释指定预期类型,那么也会引发错误:

// @ts-check

/** @type {HTMLInputElement} */
const myInput = document.getElementById('myInput');
myInput.value = 'foobar';

Type 'HTMLElement' is not assignable to type 'HTMLInputElement'.类型“HTMLElement”不可分配给类型“HTMLInputElement”。
Property 'accept' is missing in type 'HTMLElement'. “HTMLElement”类型中缺少属性“accept”。

If I was in TS, I could use document.getElementById('myInput') as HTMLInputElement to tell it that I expect this type.如果我在 TS 中,我可以使用document.getElementById('myInput') as HTMLInputElement来告诉它我期望这种类型。

How do I do this in JS with @ts-check ?如何在 JS 中使用@ts-check执行此操作?

The fix for this is to put the @type declaration between the variable and the retrieval, and adding () . 解决方法是将@type声明放在变量和检索之间,并添加()

Like this: 像这样:

// @ts-check

const myInput = /** @type {HTMLInputElement} */ (document.getElementById('myInput'));
myInput.value = 'foobar';

This syntax is fairly clunky and horrible, but they've closed the bug so I guess the above syntax is the official way to handle this. 这个语法相当笨拙和可怕,但是他们已经解决了这个问题,所以我想上面的语法是解决这个问题的官方方法。

You can use a runtime check if you want to be absolutely sure, this also persuades typescript that the assignment is safe. 如果您想绝对确定,可以使用运行时检查,这也可以使打字稿确信该分配是安全的。

const myInput = document.getElementById('myInput');
if (myInput instanceof HTMLInputElement) {
    myInput.value = 'foobar';
}

The answer by @Keith is excellent, but it only covers individual Element nodes via: @Keith 的答案非常好,但它仅通过以下方式涵盖单个Element节点:

  • @type {HTMLInputElement}

We also need to deal with HTMLCollections - which we can do via:我们还需要处理HTMLCollections - 我们可以通过以下方式完成:

  • @type {HTMLCollectionOf<Element>}

Faced with a long file of javascript which may contain any number of Element and HTMLCollection captures, we can take advantage of the following two search and replace Regexes:面对可能包含任意数量的ElementHTMLCollection捕获的 javascript 长文件,我们可以利用以下两个搜索和替换正则表达式:

Find Element captures:查找元素捕获:

((let|const|var)\s([^\s=]+)\s?=)\s?(([^\.]+)\.(((get|query)[^\(]+\(([^\)]+\))\[\d+\])|(getElementById|querySelector)\(([^\)]+\))))

Replace with:用。。。来代替:

$1 /** @type {HTMLInputElement} */ ($4)

Then...然后...

Find HTMLCollection captures:查找 HTMLCollection 捕获:

((let|const|var)\s([^\s=]+)\s?=)\s?(document\.(get|query)[^\(]+\(([^\)]+\)))

Replace with:用。。。来代替:

$1 /** @type {HTMLCollectionOf<Element>} */ ($4)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM