The error “Property ‘offsetTop’ does not exist on type ‘Element’” occurs when we try to access the offsetTop
property on an element that has a type of Element
. To solve the error, use a type assertion to type the element as HTMLElement
before accessing the property.
This is the index.html
file for the examples in this article.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<div id="box">Hello world</div>
<script src="./src/index.ts"></script>
</body>
</html>
And here is an example of how the error occurs in the index.ts
file.
// 👇️ const box: Element | null
const box = document.querySelector('#box');
if (box != null) {
// ⛔️ Property 'offsetTop' does not exist on type 'Element'.ts(2339)
const offsetTop = box.offsetTop;
console.log(offsetTop);
}
The reason we got the error is that the return type of the document.querySelector method is Element | null
and the offsetTop property doesn’t exist on the Element
type.
To solve the error, use a type assertion to type the element as an HTMLElement
.
const box = document.querySelector('#box') as HTMLElement | null;
if (box != null) {
const offsetTop = box.offsetTop;
console.log(offsetTop); // 👉️ 8
}
If you used the document.getElementsByClassName method, type the collection as HTMLCollectionOf<HTMLElement>
.
// 👇️ with getElementsByClassName
// type as HTMLCollectionOf<HTMLElement>
const boxes = document.getElementsByClassName(
'box',
) as HTMLCollectionOf<HTMLElement>;
for (let i = 0; i < boxes.length; i++) {
const offsetTop = boxes[i].offsetTop;
console.log(offsetTop);
}
We could have also been more specific and typed the element as HTMLDivElement
, because we’re working with a div
in the example.
Type assertions are used when we have information about the type of a value that TypeScript can’t know about.
We effectively tell TypeScript that the box
variable stores anHTMLElement
or a null
value and not to worry about it.
We used a union type to specify that the variable could still be null
, because if an HTML element with the provided selector does not exist in the DOM, the querySelector()
method returns a null
value.
We used a simple if
statement that serves as a type guard to make sure the box
variable doesn’t store a null
value before accessing its offsetTop
property.
const box = document.querySelector('#box') as HTMLElement | null;
// 👉️ box has type HTMLElement or null here
if (box != null) {
// 👉️ box has type HTMLElement here
const offsetTop = box.offsetTop;
console.log(offsetTop); // 👉️ 8
}
TypeScript knows that the box
variable has a type of HTMLElement
in the if
block and allows us to directly access its offsetTop
property.
It’s always a best practice to include null
in the type assertion because the querySelector
method would return null
if no element with the provided selector was found.
You might also use the optional chaining (?.) operator to short-circuit if the reference is equal to null
or undefined
const box = document.querySelector('#box') as HTMLElement | null;
// 👇️ using optional chaining (?.)
const offsetTop = box?.offsetTop;
console.log(offsetTop); // 👉️ 8
The optional chaining operator short-circuits returning undefined
if the reference is equal to null
or undefined
.
In other words, if the box
variable stores a null
value, we won’t attempt to access the offsetTop
property on null
and get a runtime error.
Conclusion
The error “Property ‘offsetTop’ does not exist on type ‘Element’” occurs when we try to access the offsetTop
property on an element that has a type of Element
. To solve the error, use a type assertion to type the element as HTMLElement
before accessing the property.