[英]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:面对可能包含任意数量的Element和HTMLCollection捕获的 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.