@abstract (also spelled @virtual) is a JSDoc documentation tag for a class or method that subclasses are meant to fill in. TypeScript 5.9 does not act on it in a .js file: creating the tagged class with new passes, and so does a subclass that never defines the tagged method.
JavaScript has no abstract keyword, and TypeScript's keyword is an error in a .js file, so the compile-time version of this check is not available. The working pattern is a base class that refuses direct construction at run time and an abstract method whose body throws.
At a glance
| Use | JSDoc in a .js file | TypeScript in a .ts file |
|---|---|---|
| An abstract class | /** @abstract */
class Shape {} | abstract class Shape {} |
| An abstract method | /** @abstract */
area() { throw new Error("…"); } | abstract area(): number; |
Examples
/** @abstract */
export class Shape {
/**
* @abstract
* @returns {number}
*/
area() {
throw new Error("Shape.area must be implemented");
}
}
// TypeScript accepts both lines: the @abstract tags change nothing.
export const blank = new Shape();
export class Square extends Shape {}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} export class Shape {
constructor() {
if (new.target === Shape) throw new TypeError("Shape is abstract");
}
/** @returns {number} */
area() {
throw new Error(`${this.constructor.name} must implement area()`);
}
}
export class Square extends Shape {
/** @param {number} side */
constructor(side) {
super();
this.side = side;
}
area() {
return this.side ** 2;
}
}
new Square(3).area();export abstract class Shape {
abstract area(): number;
}
export class Square extends Shape {
side: number;
constructor(side: number) {
super();
this.side = side;
}
area() {
return this.side ** 2;
}
}
new Square(3).area();jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} How we tested it
The first example tags a class and its method @abstract, then calls new Shape() and declares a subclass without area(). In a .ts file with the abstract keyword those two lines are errors (TS2511, "Cannot create an instance of an abstract class", and TS2515 for the missing member). With the JSDoc tag, tsc reports nothing, which is how we know the tag changes nothing. TypeScript's JSDoc parser has no special case for it, so editors show it as plain text in the hover.
Abstract classes in JavaScript
new.target holds the class that new was called on. A base constructor that throws when new.target === Shape blocks new Shape() but allows new Square(), because new.target is then Square.
Give the abstract method its JSDoc return type and a body that throws. Every override is checked against that return type like any other method, and a subclass that forgets the method fails the first time it is called, with a message that names the class.
Gotchas
- The
abstractkeyword is TypeScript syntax: in a.jsfile,abstract class Shape {}is an error (TS8009, "The 'abstract' modifier can only be used in TypeScript files"). - The run-time check only fires when the code runs. Tests that create every subclass once are the JavaScript stand-in for the compile-time check.
Questions
Does TypeScript support @abstract in JSDoc?
No. In TypeScript 5.9 the tag shows up as text in editor hovers and has no effect on checking. The handbook's JSDoc Reference does not list it among the supported tags.
Sources
- @abstract · JSDoc
- JSDoc Reference · TypeScript handbook
- Classes: abstract classes and members · TypeScript handbook
Last reviewed 20 October 2026.