-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Support @abstract
JSDoc tag
#17227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Adding a bit more to this, it would be nice if For example, with this code: /**
* @abstract
*/
class Integer {
/**
* @abstract
* @return {number} A number.
*/
get() {}
}
class FortyTwo extends Integer {
get() {
return 42
}
}
/**
* @returns {number} The return.
*/
function getFortyTwo() {
const number = new FortyTwo();
return number.get();
}
|
Here’s an elaborate yet workable recipe for how I’ve worked around my desire for
I don’t love this approach, but I do appreciate the added type-checking for my subclasses. Example CodeSvgRenderer.d.tsexport declare abstract class SvgRenderer {
public name: string;
public data?: Record<string, any>;
constructor(name: string, data?: Record<string, any>);
public abstract render(): SVGSVGElement;
public update(data: Record<string, any>): void;
public serialize: () => string;
public rasterize: () => Promise<Buffer>;
} SvgRenderer.jsimport { serialize, rasterize } from ‘./utils’;
/** @abstract */
export class SvgRenderer {
/**
* @param {string} name
* @param {Record<string, any>} [data]
*/
constructor(name, data) {
this.name = name;
this.data = data;
}
/**
* @public
* @param {Record<string, any>} data
*/
update(data) {
if (data) {
this.data = data;
} else {
console.warn('update(): `data` is `undefined');
}
}
// Notice that I’ve marked this method as `@abstract`,
// but have _not_ added any JSDoc type annotations!
// This is really just a human-readable reminder for now, however.
/** @abstract */
render() {
throw new Error('Not implemented');
}
/**
* @public
* @returns {string}
*/
serialize() {
// TODO: Remove @ts-ignore after Microsoft/TypeScript#17227 is fixed
/** @see https://github.com/Microsoft/TypeScript/issues/17227 */
// @ts-ignore
return serialize(this.render()); // error ts(2345)
}
/**
* @public
* @returns {Promise<Buffer>}
*/
rasterize() {
// TODO: Remove @ts-ignore after Microsoft/TypeScript#17227 is fixed
/** @see https://github.com/Microsoft/TypeScript/issues/17227 */
// @ts-ignore
return rasterize(this.render());
}
} ExampleRenderer.jsimport { SvgRenderer } from './SvgRenderer';
export class ExampleRenderer extends SvgRenderer {} With both SvgRenderer.js and SvgRenderer.d.ts in place, I get the following error in the above ExampleRenderer.js, which is exactly what I want in this case:
(Note for posterity: this is with TypeScript 3.4.3.) |
hey thanks, yes i also do this for now ! I have nothing against mixing |
Spurred by @a-tarasyuk 's recent PR, I did a survey of Here's what I found: Abstract methods in abstract classes?No.
Abstract method bodies?Empty or a single throw. The top two abstract method bodies were empty (40) and a single throw (17). Webpack had another 17 require/throw statement pairs that could be inlined to a single throw. The leftovers (8) were on methods that were mistakenly (or wishfully?) declared abstract, plus a single deprecated method in webpack that threw unless it could detect it was being used from a deprecated location, in which case it ran the deprecated code. |
Based on discussion with @a-tarasyuk, after reading his PR #42186 and after surveying usage: we're not going to take PRs for this bug unless usage ticks up considerably and there is a bigger demand for it. I believe current usage is hugely depressed by the existence of Typescript, since people who want this feature likely want all the other OO decorations that Typescript adds, like I'm going to leave this open because things may change in another decade or two. |
When trying to migrate the type checker of a large JS codebase from Closure Compiler to Typescript, we found that lacking @abstract support is the major blocker. It would be great if the PR can be merged, and we are willing to test it for our codebase if needed :) |
It also helps with code like: // base.d.ts
export interface SomeValue {
foo: string;
bar: number;
}
export abstract class Base {
abstract doStuff(): string;
abstract getSomeValue(): SomeValue;
} // DoStuff.js
import { Base } from "./base.js";
/** @abstract */
export class DoStuff extends Base {
doStuff(callback) {
const someValue = this.getSomeValue();
return `foo: ${JSON.stringify(someValue.foo)}, bar: ${JSON.stringify(someValue.bar)}`;
}
} Currently, TypeScript complains that the |
{
"devDependencies": {
"typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/98652/artifacts?artifactName=tgz&fileId=606CC13BB0AC03ADD769068E6B431AFC3E8D76BC07CDFE3667DFE540A6500AC002&fileName=/typescript-4.3.0-insiders.20210316.tgz"
}
}
|
(This is based on the same code base with @ShikChen)
Tried the newer build in the last comment and it works well for our usage of @abstract.
We're only using it to mark the pure interface class, which only has bunch of abstract methods and intended to be subclassed. All the body are empty, and we have @abstract marker on both the class and all the methods.
Yes, we're planning to transition to TypeScript eventually.
Since the codebase is ~18k loc, it'd take some time to fully migrate to TypeScript. We're currently trying to fix as many errors from tsc as possible before fully transition to TypeScript syntax. The current major blocker we have is if the abstract method also has @return, tsc complains about the empty body must return a value (TS2355). We'll be happy as long as TypeScript doesn't complain about that as long as the method is also marked as @abstract. |
My suggestion to workaround a method with both /**
* @returns {never}
*/
function abstract() {
throw new Error("This method was declared as abstract and cannot be called directly.")
}
/**
* @abstract
*/
class Foo {
/**
* @abstract
* @returns {string}
*/
method() {
abstract();
}
} TypeScript won't enforce the |
@DanielRosenwasser Sadly closure compiler doesn't like the workaround, and reports error:
|
It was an interesting experiment, however, it seems there are no reasons to continue working on it. I agree with @sandersn's points about this feature. Therefore, I closed PR in order not to mislead users who use PR directly. |
Migrate the CCA build from closure compiler to TypeScript. Also fix all remaining TypeScript errors that are hard to be fixed while satisfying both closure compiler and TypeScript. The one issue that contributes to most of the code change is that TypeScript doesn't properly support @abstract jsdoc tag [1], and complains that methods with return types should return something. We manually added a runtime assertNotReached() to those functions to get rid of the warning. We can refactor most usage to proper TypeScript interface later when doing per-file migrations. Also updates cca.py {tsc,deploy} to encompass the extra tsc pass. There are four files that due to jsdoc typing limitation can't be correctly typed in jsdoc. Those files are migrated to .ts. And since TypeScript doesn't recognize the jsdoc types in .ts files, all types are inlined with help from ts language server refactor support. [1]: microsoft/TypeScript#17227 Bug: b:172340451 Test: tast run <ip> camera.CCAUISmoke* camera.CCAUIStress* Change-Id: Ic6047744fb85bee2d5519cff88a861df75263dc0 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3090445 Commit-Queue: Pi-Hsun Shih <[email protected]> Reviewed-by: Zentaro Kavanagh <[email protected]> Reviewed-by: Shik Chen <[email protected]> Cr-Commit-Position: refs/heads/main@{#948458}
@sandersn Did you count the plain JS code bases that have abstract classes and methods, but that do not use I'm working on https://github.com/nasa/openmct, which has a number of abstract classes with abstract methods, not marked with comments. There is currently no intent to move the project to TypeScript, but adding some type support for IDEs as we develop, little by little, would be really nice. I am willing to test the feature in the PR, to provide the "buyin" you mentioned. |
@trusktr I didn't think to see how many people were creating abstract classes/methods without using |
Any updates on this? Is there a way to retrieve the content from #42186? |
Nothing crazy, probably what you might imagine: class Base {
foo() {
throw new Error('implement in subclass')
}
}
class Sub extends Base {
foo() { return something }
} Having a working |
TypeScript Version: nightly (2.5.0-dev.20170712)
Code
Expected behavior:
Error.
Actual behavior:
No error.
The text was updated successfully, but these errors were encountered: