An import statement in a .js file is a real import: it runs when the module loads and needs a value at the other end. A @typedef or an interface from a .d.ts file is not a value, so import { LineItem } from "./types.js" is TS18042, and the message suggests the import() type form instead.
Since TypeScript 5.5, the @import tag says the same thing with the syntax of an import statement, and it disappears at run time.
At a glance
| Code | TS18042 |
|---|---|
| Message | '{0}' is a type and cannot be imported in JavaScript files. Use '{1}' in a JSDoc type annotation. |
| TypeScript's category | error |
| Listed under | JavaScript files only |
| Turned on by | No option: every checked file reports it |
| In .js files | Reported when the file is checked: checkJs in jsconfig.json, or // @ts-check at the top of the file |
The message is TypeScript's own text from its diagnostic messages file (Apache-2.0); {0} and {1} are filled in by tsc for each error.
What it looks like
import { LineItem } from "./types.js";error TS18042: 'LineItem' is a type and cannot be imported in JavaScript files. Use 'import("./types.js").LineItem' in a JSDoc type annotation.
/** @param {LineItem[]} items */
export function count(items) {
return items.reduce((n, item) => n + item.quantity, 0);
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["**/*.js"]
} What causes it
- Code moved from a
.tsfile, whereimport { Type }is fine because the import is erased. - An import of a name that used to be a value and is now only a type.
How to fix it
Use @import for types
/** @import { LineItem } from "./types.js" */ brings the type into scope for every JSDoc tag in the file. On TypeScript before 5.5, write import("./types.js").LineItem in the tags, or a @typedef that aliases it.
/** @import { LineItem } from "./types.js" */
/** @param {LineItem[]} items */
export function count(items) {
return items.reduce((n, item) => n + item.quantity, 0);
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["**/*.js"]
} Gotchas
- This site's tests found TS18042 with and without
verbatimModuleSyntax: it is about JavaScript files, not about that option. - A name in
@importthat is never used is not checked at all, so a typo there stays hidden until a tag uses it.
Sources
- TypeScript 5.5: the @import tag · TypeScript handbook
- JSDoc Reference: import types · TypeScript handbook
- diagnosticMessages.json (TypeScript 5.9.3) · TypeScript on GitHub
Last reviewed 21 October 2026.