46

Is there a way to make TypeScript not throw the error 'TS2339: property value does not exist on type Element' for code like this:

myRow.querySelector('.my-class').value = myVal

Casting as < HTMLInputElement > Causes the code to break entirely.

Typescript seems to not handle things involving the DOM well in general, unless I'm missing something; ie it chooses specific over general for functions that could return any element.

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Turtles Are Cute
  • 3,200
  • 6
  • 30
  • 38

4 Answers4

82

The querySelector method returns Element | null.
If you're not using strictNullChecks then Element, and it doesn't have the value member.

And so casting it to HTMLInputElement as I wrote in my comment works:

let myRow = document.getElementById('my-row');
(myRow.querySelector('.myClass') as HTMLInputElement).value = " a vaule";

The error you are receiving is a result of forgetting the semicolon at the end of the first line, what happens is that the compiler thinks that you're trying to do this:

document.getElementById('my-row')(myRow.querySelector('.myClass') as HTMLInputElement)

Don't forget to end lines with semicolons.


Edit

The querySelector method is generic so you can also do:

document.getElementById('my-row').querySelector<HTMLInputElement>('.myClass').value

And in case of strictNullChecks if you're sure the element is there you can use the Non-null assertion operator:

document.getElementById('my-row')!.querySelector<HTMLInputElement>('.myClass')!.value
Nitzan Tomer
  • 155,636
  • 47
  • 315
  • 299
  • Thanks; that works. Nailed it on the semicolon. Do you know why that's required? – Turtles Are Cute Mar 26 '17 at 23:40
  • http://stackoverflow.com/questions/444080/do-you-recommend-using-semicolons-after-every-statement-in-javascript – Nitzan Tomer Mar 26 '17 at 23:46
  • Per this page: https://github.com/rse/es6-features, "Both ECMAScript 6 and all tools (including compressors) perfectly support automatic semicolon inference/insertion nowadays. As a consequence, ECMAScript 6 coders nowadays can get rid of nearly all semicolons and remove clutter from their source code." Ie, it's weird to require a semicolon in this specific case. – Turtles Are Cute Mar 28 '17 at 17:46
  • 2
    "...get rid of **nearly all** semicolons". In your case it makes a difference – Nitzan Tomer Mar 28 '17 at 23:53
  • Do I always have to cast when I use this element? What if I'm quite sure that this element exists on my page. Can I already specify its type when I first declare and query it. – xji Jul 07 '18 at 16:35
  • document.getElementById('my-row')!.querySelector('.myClass')!.value -> this still gives me error "Untyped function calls may not accept type arguments." while building – zainul Sep 09 '20 at 07:34
  • Why does the querySelector return element? The MDN documentation says that it returns an HTMLElement. – dwjohnston Sep 29 '20 at 06:06
  • I don't like this answer. In your second example, what if it found a `div` element? Your subsequent types would be wrong. – dwjohnston Sep 29 '20 at 06:08
  • @dwjohnston mdn is nice and all, but still the typescript definitions state that `document.querySelector` returns `Element | null`, that won't change based on you liking my answer or not. also, there is no "finding of an element" in typescript. ts is for complication time only. the compiler has no way of knowing what will be found at runtime. therefor the the `querySelector` is generic and it's up to the developer to know what is going to be there at runtime. you should read/understand more before posting wrong statements – Nitzan Tomer Sep 29 '20 at 11:14
  • @NitzanTomer re: 'The compiler has no idea what will be returned at runtime' - I agree, but your answer should have that caveat with the second suggestion. The real safe solution would be that make some kind of assertions about the found element to check that it really is an HTMLInputElement, before casting it as such. – dwjohnston Sep 29 '20 at 12:25
  • @dwjohnston you're wrong again. i mean, you can have assertions in you code, but why would you want to? do you make that assertion in js when you do `const input = document.getElementById("someInputElementId")` that `input` is indeed of the right type or do you trust that your html code is as you wrote it? the whole idea of the generic constraint is to give the developer the ability to tell the compiler that he knows better in this case. the op has mentioned that his element is `HTMLInputElement`, so that's what i used. – Nitzan Tomer Sep 29 '20 at 12:35
  • the clue as HTMLInputElement helped me to fix my issue. thanks – GuyFromChennai Sep 07 '21 at 11:30
  • @NitzanTomer you said "trust that your html code", but who says it is "your" html code? What if a team member changes it? What if you change it, but forget to update your TS code? What if a `querySelectorAll` can actually return different elements? What if you code a web scraper and you really cannot know the HTML code? In all those cases you would waste time to find the error, that could be avoided by coding "really" type safe. – Toxiro Mar 29 '22 at 01:48
  • I simply can't get through that thing of leaving semicolons. Maybe it's because I come from C++, where your freedom ranges between the rules. – Niki Romagnoli Jun 23 '22 at 15:20
3

The other answers here did not help. I found elsewhere and via trial and error that

  1. querySelector is an HTMLElement
  2. querySelectorAll is an array of them HTMLElement[]
sections: HTMLElement[] = [];

this.sections = someElement.nativeElement.querySelectorAll('li') as HTMLElement[];
Ben Racicot
  • 5,332
  • 12
  • 66
  • 130
1

I did it like this:

const myClass: HTMLInputElement | null = document.querySelector(".my-class") as HTMLInputElement;

if (myClass) {
    myClass.value = myVal;
}
Patrick Koorevaar
  • 1,219
  • 15
  • 24
0
//  define
export const $ = <T>(selector, scope = document): T =>
  scope.querySelector(selector);


//  use
const $account: HTMLInputElement = $("#login-account");

// example tips for  .value
const account = $account.value
ifredom
  • 979
  • 9
  • 6
  • 1
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. You can find more information on how to write good answers in the help center: https://stackoverflow.com/help/how-to-answer . Good luck – nima Nov 07 '21 at 13:51