I've got some simple browser-side JS code, and thought I'd try using @ts-check to pick out any fluff. Some valid bugs were found, and I've added js-doc parameter type information as well. I don't want a transpile step so this needs to be vanilla Javascript.
When I access DOM element properties I get errors, because TS doesn't know the real type of these elements.
s.YWindows = document.getElementById("rows-input").valueAsNumber
gives...
Property 'valueAsNumber' does not exist on type 'HTMLElement'
I thought I could use a JSDoc type hint to resolve that, but it only moves the problem.
/** @type {HTMLInputElement} */
let r = document.getElementById("rows-input")
s.YWindows = r.valueAsNumber
Type 'HTMLElement' is missing the following properties from type 'HTMLInputElement': accept, align, alt, autocomplete, and 52 more.
Suggestions, or do I just have to disable around this section somehow?
CodePudding user response:
It is (currently) not possible to have TypeScript understand this situation. The @types
hint applies to the variable being declared, but do not change the return type of the function that initializes its value.
You can use //@ts-ignore
just above a line to have TS ignore all errors that can occur in this line. For example :
/** @type {{HTMLInputElement}} */
//@ts-ignore
let r = document.getElementById("rows-input");
s.YWindows = r.valueAsNumber;
This would still tell to TS that r
has an HTMLInputElement
type, but it will ignore the mismatch between r
's type and getElementById
's return type.
One drawback of that is that you may end up using //@ts-ignore
quite often.
CodePudding user response:
The TypeScript compiler supports inline type casting when using JSDoc syntax. From the link:
TypeScript borrows cast syntax from Google Closure. This lets you cast types to other types by adding a
@type
tag before any parenthesized expression./** * @type {number | string} */ var numberOrString = Math.random() < 0.5 ? "hello" : 100; var typeAssertedNumber = /** @type {number} */ (numberOrString);
You can even cast to
const
just like TypeScript:let one = /** @type {const} */(1);
Here's an example which addresses the details in your question:
/** @type {{ YWindows?: number }} */
const s = {};
// It's not safe to assume that the ID exists in the document,
// so null must be included in the union:
const input = /** @type {HTMLInputElement | null} */(document.getElementById("rows-input"));
if (input) {
s.YWindows; // number | undefined
s.YWindows = input.valueAsNumber;
s.YWindows; // number
}
s.YWindows; // number | undefined