admin管理员组文章数量:1435859
Converting my JS to TS strict mode.
The following syntax looks fine to me but TS is complaining in the for
loop on allSubMenus
with:
[ts] Type 'NodeListOf<Element>' is not an array type or a string type.
What am I missing?
function subAct(target:Node){
const allSubMenus : NodeListOf<Element> = document.querySelectorAll('.subMenuItems')
for (const sub of allSubMenus){
sub.classList.remove('active')
}
}
Converting my JS to TS strict mode.
The following syntax looks fine to me but TS is complaining in the for
loop on allSubMenus
with:
[ts] Type 'NodeListOf<Element>' is not an array type or a string type.
What am I missing?
function subAct(target:Node){
const allSubMenus : NodeListOf<Element> = document.querySelectorAll('.subMenuItems')
for (const sub of allSubMenus){
sub.classList.remove('active')
}
}
Share
Improve this question
edited Jul 15, 2020 at 8:38
jonrsharpe
122k30 gold badges264 silver badges472 bronze badges
asked Aug 7, 2018 at 9:58
SamSam
1,8284 gold badges32 silver badges58 bronze badges
7 Answers
Reset to default 44You need to set the target
compiler option to es6
or higher for NodeListOf<T>
to be iterable.
According to your typescript target compiler, parsing error can be occured.
The for-of loop, introduced in the sixth edition of EcmaScript (ES6). Thus, old browsers' JS engine can not understand for-of loop syntax. https://hacks.mozilla.org/2015/04/es6-in-depth-iterators-and-the-for-of-loop/
To solve this issue,
if you support latest modern browsers(>=ES6) only
change your TS target
//tsconfig.json
{
"compilerOptions": {
"target": "es6" //above es6 like ES2015,ES2018 ...
}
}
if you support old browsers(<=ES5)
I presume that you are using next environment.
//.tsconfig.json
{
"compilerOptions": {
"target": "es5"
}
}
- To keep for-of loop, use as any syntax
Note: "as any" will cast collection(Objects) to array and this will affect some type features within "for" scope.
//.ts
const allSubMenus : NodeListOf<SpecifiedElement> = document.querySelectorAll('.subMenuItems')
for (const sub of allSubMenus as any){ // then will pass compiler
sub.classList.remove('active')
}
The above TS script will be compiled to
//.js output
var allSubMenus = document.querySelectorAll('.subMenuItems');
for (var _a = 0, _b = forms; _a < _b.length; _a++) {
var sub = _b[_a];
sub.classList.remove('active');
}
https://stackblitz.com/edit/node-ywn1bq?file=main.js
- Use classic for-loop syntax
const allSubMenus : NodeListOf<SpecifiedElement> = document.querySelectorAll('.subMenuItems')
for (let i = 0; i < allSubMenus.length; i++) {
allSubMenus[i].classList.remove('active');
}
<Element>
In addition to the above, to avoid the following warning,
Property '<property name>' does not exist on type 'Element'
you may specify <Element> if you know element type and type define exists.
//for example,
NodeListOf<Element> => NodeListOf<HTMLFormElement>
ECMAScript(ES) history
https://codeburst.io/javascript-wtf-is-es6-es8-es-2017-ecmascript-dca859e4821c
You could try
const allSubMenus : NodeListOf<Element> = document.querySelectorAll('.subMenuItems')
Array.from(allSubMenus, subMenu => {/* */})
Set "downlevelIteration": true
in compilerOptions in your tsconfig.json file.
From https://www.typescriptlang.org/tsconfig#downlevelIteration
Downleveling is TypeScript’s term for transpiling to an older version of JavaScript. This flag is to enable support for a more accurate implementation of how modern JavaScript iterates through new concepts in older JavaScript runtimes
You can iterate over a NodeListOf
with the forEach
method.
const allSubMenus : NodeListOf<Element> = document.querySelectorAll('.subMenuItems')
allSubMenus.forEach(sub => sub.classList.remove('active'))
Source: https://microsoft.github.io/PowerBI-JavaScript/interfaces/_node_modules_typedoc_node_modules_typescript_lib_lib_dom_d_.nodelistof.html#foreach
while compiling your code you may choose target: ES2017
or target: ES2015
. also you can set this property in tsconfig.json
file unser compilerOptions
.
So here is the command line code for that:
npx tsc path/to/file.ts --target ES2015
TIP:
if you are using babel along side with typescript, it is totally recommended that you always make typescript to compile to latest version of Javascript, and then let babel handles rest of transpiring process. With this technique you add another lever of assurance of supportive level to older browsers since typescript is not ok to compile the code that would run in for example ie6; so babel comes to rescue here and make you yo make sure that your js
code would run in even ie < 9 with it's helpful polyfills and other mechanisms that it takes to work!
So keep in mind that:
Always let typescript compiles your code to latest javascript ( by setting target: ES2017
) and let babel transpiles your js code to support older browsers ( separate concerns properly and let each one does the related job).
This assumes you want to keep ES5 target (if not, upgrading it to ES6 will solve the issue as well).
- Use
for
loop
function subAct(target:Node){
const allSubMenus = document.querySelectorAll('.subMenuItems');
for (let i = 0; i < allSubMenus.length; i += 1){
const sub = allSubMenus[i];
sub.classList.remove('active')
}
}
- Use
Array.from
In order to use this, you have to add ES2015.core
to compilerOptions.lib
and add polyfill for Array.prototype.from
Note that this will loop on the collection twice - the first method is better.
function subAct(target:Node){
const allSubMenus = Array.from(document.querySelectorAll('.subMenuItems'));
for (const sub of allSubMenus){
sub.classList.remove('active')
}
}
本文标签:
版权声明:本文标题:javascript - Typescript,'NodeListOf<Element>' is not an array type or a string type - Stack Overfl 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1737064134a1961157.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论