A @type comment directly before a parenthesized expression changes the expression's type: /** @type {HTMLInputElement} */ (document.querySelector("#email")) is the JavaScript spelling of document.querySelector("#email") as HTMLInputElement. TypeScript 2.5 added the form.
Both parts are required. Without the parentheses the comment is just a comment, and the value keeps its own type, Element | null, as the second example shows with two errors on the next line.
At a glance
| Use | JSDoc in a .js file | TypeScript in a .ts file |
|---|---|---|
| A cast | /** @type {HTMLInputElement} */ (document.querySelector("#email")) | document.querySelector("#email") as HTMLInputElement |
| Through unknown | /** @type {Target} */ (/** @type {unknown} */ (value)) | value as unknown as Target |
Examples
const email = /** @type {HTMLInputElement} */ (document.querySelector("#email"));
const form = /** @type {HTMLFormElement} */ (document.getElementById("signup"));
form.addEventListener("submit", (event) => {
if (!email.value.includes("@")) {
event.preventDefault();
email.setCustomValidity("Enter an email address");
email.reportValidity();
}
});
export {};const email = document.querySelector("#email") as HTMLInputElement;
const form = document.getElementById("signup") as HTMLFormElement;
form.addEventListener("submit", (event) => {
if (!email.value.includes("@")) {
event.preventDefault();
email.setCustomValidity("Enter an email address");
email.reportValidity();
}
});
export {};jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} const field = /** @type {HTMLInputElement} */ document.querySelector("#q");
field.value = "";error TS18047: 'field' is possibly 'null'.error TS2339: Property 'value' does not exist on type 'Element'.
export {};jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} const fromForm = "5";
const quantity = /** @type {number} */ (fromForm);error TS2352: Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
const parsed = Number(fromForm);
export { quantity, parsed };jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} const field = document.querySelector("#q") as HTMLInputElement;error TS8016: Type assertion expressions can only be used in TypeScript files.
export { field };jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} What a cast checks
Very little. TypeScript only rejects casts between types that do not overlap at all, such as a string to a number (TS2352, "Conversion of type 'string' to type 'number' may be a mistake…"). Anything plausible passes: a cast to HTMLInputElement is accepted even if the selector matches a <div>, or nothing.
For data from outside (JSON, form values, postMessage), prefer a check that narrows, a type predicate or an assertion function, so a wrong assumption fails at once, with a clear message, instead of somewhere later.
as is TypeScript syntax
value as Type is an error in a .js file (TS8016, "Type assertion expressions can only be used in TypeScript files"), as the last example shows.
Gotchas
- After running a formatter over a file full of casts, check that the parentheses survived; Prettier, for one, keeps them when a type comment is attached.
- To cast between unrelated types on purpose, go through
unknownfirst, as the TS2352 message suggests.
Questions
How do I cast a type in JavaScript with JSDoc?
Put /** @type {Type} */ before the expression and wrap the expression in parentheses: /** @type {Type} */ (expression).
Sources
- TypeScript 2.5: type assertion/cast syntax in checkJs mode · TypeScript release notes
- JSDoc Reference: casts · TypeScript handbook
- Everyday Types: type assertions · TypeScript handbook
Last reviewed 20 October 2026.