-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Document class types/constructor types #1349
Comments
Is |
In VSCode, the assignment works (passing a constructor/class to a function expecting a
This is keeping me from using VSCode's static type checking |
Closure Compiler has a syntax for this: https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler#function-new-type And TypeScript / VS Code even understands it. |
I'm using jsdoc together with typescript since it let's me to write plain old javascript and do the typechecking against the jsdoc. The syntax:
seems to be working fine in that environment. In my case (and i think is a very common case) I'm documenting what a native library provides. The module is exporting an object which properties are classes so this was mandatory. Unfortunately this is not valid jsdoc code and I dont have a way to exclude some comments from the jsdoc parser :( I think this is very very important |
Have you tried the |
@thw0rted that would work only in the case that I do new SomeClass but not in the case I want to call static methods / static members (example below). What we really needs is typeof that BTW is supported by typescript although not documented. I'M WRITING A JSDOC PLUGIN TO CHANGE Example of static methods in which
|
Done ! :) https://github.com/cancerberoSgx/jsdoc-typeof-plugin ... Now I can have types that refer classes, something very very basic that jsdoc should support. |
This feature is highly missed. At my company, we use the convention |
@dcleao in my team we also started using Class but that won't work with typechecking validation in editors like webstorm, vscode, atom, etc. I think typeof is not a proprietary thing of webstorm or vscode but is more like a typescript / closure compiler "standard". IN the case of eslint, probably you should issue that team or ask them to support that as an enhancement . |
+1 for |
+1 for |
I think today TypeScript is the defacto "jsdoc" standard. Great part of jsdoc grammar is currently defined in the language itself and new jsdoc grammar for type-related things like this too. Since is a formal grammar definition, IMO people will tend to move away from this project's grammar, particularly for type related semantics. The TypeScript AST for
is something like this - sorry for the indentation
Since the objective of TypeScript is typecheck, they needed to create that syntax and used the same grammar that's already present in TypeScript for that. In other situations they use syntax already in TS for jsdocs, for example, generics - they don't support @template but the well known syntax {Array}. On the other hand TS syntax don't support documentation-related semantic like @link, @example, etc. My point is, for those who want typechecking and already have jsdocs comments, give TypeScript a try. No modifications are needed in a js project, can be done gradually mixing js and ts files, and compilation / Type errors can be configured pretty flexible. Also jsdocs itself ends up being simpler since in TS, jsdocs don't have types references or to explain what's you are documenting @Class @method are no needed. That simplify the comments a lot. I wonder if there are any plans in this project to catch up or support more of current TypeScript jsdocs syntax. An interesting proiect could be parse js code using TypeScript compiler and generate a AST compatible with the syntax of this project (so I can use themes, etc to document TS/JS projects). |
This comment was marked as spam.
This comment was marked as spam.
how to add restrictions like i am waiting for classes that extends certain other classes? |
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
@aaclayton is typeof not working for you? |
edit: ah forget about this, I thought I was commenting on the TypeScript repo. To answer the original question. You can type functions like /**
* @template {View} T
* @template {any[]} U
* @param {new (...args: U) => T} ViewClass
* @param {U} [data]
* @return {T}
*/
function createView(ViewClass, ...data) {
return new ViewClass(...data)
} If you do it like this, parameter hints for the Or if you don't wish to use /**
* @param {new (...args: any[]) => View} ViewClass
* @param {any[]} [data]
* @return {View}
*/
function createView(ViewClass, ...data) {
return new ViewClass(...data)
} But types will be less strict, since the |
@wmertens it might work with a plugin, but it does not work natively in JSDoc, if I annotate something as
|
Ah right - JSDoc can't handle typescript syntax, makes sense. |
Imho, JSDoc just isn't moving quickly enough to update its type parser to work with TypeScript's flavor of JSDoc. At the most basic level, the community needs something like TypeScript's |
I think it's fair to say that JSDoc has already tacitly passed the torch to Typescript. The mailing list has 5 new threads since 2017, which is coincidentally the last time the official website was updated. PR #1440 was the most recent one I could find that was not a dependency/compatibility or documentation update, also, funny enough, from 2017. There have been a couple of "is JSDoc dead" issues here, and eventually @hegemonic shows up to say that he's back and working on it again, but if there were PRs that added new features or syntax I couldn't find them. I think it's critically important to say: I'm not complaining about that! This is an open source project, with a budget of 0.00 full-time employees. I honestly appreciate the work people put into this very important project! But on the internet, if you don't swim you die, and JSDoc has not been swimming for half a decade. IMHO, the right move for any tools built on JSDoc would be to treat "Typescript flavor" as the one true syntax. (Sure would be nice if MS went ahead and adopted this project in the process...) |
Am I reading these comments correctly as a recommendation that, even for pure JS projects, it would be advisable to:
I suppose its worth a try, it's unfortunate that type of intermediary step is necessary but if it produces both valid IDE inspections and valid HTML documentation then I would view that as a victory. |
Only steps 1 and 2 should be necessary, and step 2 only if you wish other projects to use your code, noting that for step 1, TypeScript-style documentation syntax is JSDoc, it's just a different dialect of JSDoc as far as which JSDoc tags have formally defined behavior, what the types are (there are many more available in TypeScript flavor), and what the allowable syntax is (the TypeScript team tried to hew closely to JSDoc, but they avoided You can already use tools like typedoc (based on a tsdoc standard) to build docs out of plain JS and TypeScript-flavored JSDoc. For more info, I just added a Gist summary of my experiences with some references at https://gist.github.com/brettz9/17bcbfa2b7c0e4ddaac4604da4490e23 |
Just to check, do you mean only steps 1 and 2, or only steps 1 and 3? If typedoc supports vanilla JS -> HTML directly, it shouldn't be necessary to create intermediate ETA: to clarify what I said above, I'm not sure if TS-flavored-JSDoc is a totally great experience for vanilla JS projects today, but it seems likely to be the best solution going forward. I hope that TS is willing to pick up the mantle and be the standard, even if you're not writing TS, but I recognize that there may still be gaps. I just don't think that sticking to a 5+ year old spec, while JS/ES continues to evolve around it, is really sustainable for anyone. |
Step 2 is optional. You need a declaration file if you want third parties to use your code in a type-aware manner (unless DefinitelyTyped has already made type files on your behalf in which case your users can just use the types from DefinitelyTyped). I haven't been building docs lately; you'd have to check out Tools that build docs using TypeScript should, I believe, be able to parse JSDoc along the way without having to first build physical declaration files, since TypeScript is capable of processing them on their own. So I did mean 1 and 2 should be necessary, and only step 2 if you need to export types for other projects. |
I see. I look at maintaining your own typings (assuming we're talking about publishing, say, an open-source library authored in vanilla JS) as a nice to have, but not strictly necessary, and I wouldn't specifically couple it to documentation. I'd be very happy if we can just get to a place where a project that uses jsdoc to generate docs today, could spend 15 minutes hooking up e.g. typedoc or better-docs as a drop in replacement and get roughly the same output. Adding generated TS typings files to the process would be an awesome bonus. |
Let me maybe close this issue i had success with the following method const myClass = class {}
const fn = (/** @type {new () => any } takeClass) => {} so the secret source is this type: const myClass = class {}
/**
* @param {new () => myClass| } takeClass
*/
const fn = (takeClass) => {
myClass() // => correctly errors that it needs and should get called with new
} tested with current typescript 4.7 note that we explicit say => myClass so only myClass is valid in fn |
I'm 99% sure your syntax ( ETA: c.f. my many comments about this roughly 2-3 pages upthread, which I wrote 2 months ago then promptly forgot 😳 |
It is true that those types are not accepted by JSDoc's type parser, but the fact is that the development pace of TypeScript to accommodate all kinds of important needs is much faster and broader than for this particular tool, however appreciated it is for having advanced the phenomenon and served/serving as a useful tool. Note that one does not need to use TypeScript syntax in order to use the types within JSDoc comments. One can use plain JavaScript and use tools like typedoc to get documentation built similar to JSDoc, without needing a single line of TypeScript-specific syntax. (there are some current imperfections using JSDoc alone to export definition files, but plain JSDoc doesn't allow this anyways). TypeScript's form can in fact, in a sense be said to be JSDoc, as it conforms in the general structure of JSDoc blocks, but it merely follows a special dialect in its types. (As far as other forms of JSDoc "vocabulary", TypeScript's checker won't complain about tags it doesn't recognize. Although there are some tags it would ideally support but doesn't, the real "incompatibility" is just about types.) In |
I agree with Brett's comments about switching, insofar as TypeScript is active and JSDoc pretty much isn't. My point was that there are still tools that only support vanilla JSDoc and Frank needs to be aware that his TS-specific syntax could break them. It's just rehashing the discussion upthread, but I wanted to make sure Frank (and any future readers) noticed. |
For those advocating "just switch to TypeScript for docs generation", it's not simple to do. Supposing you have an existing codebase which is pure JS documented using JSDoc. You can install There's no tutorial to follow for doing this, just TypeScript advocates who misleadingly say its easy. |
I hope I didn't give the impression that "it's easy" above. The problem is that JSDoc is not being updated to reflect the rapidly evolving vanilla-JS (ES) ecosystem. If you have legacy vanilla JSDoc tooling and want to keep growing your project, unfortunately you don't have any "easy" choice. You can pick trying to hack around the missing support in JSDoc for features like the one that prompted this issue, which is hard, or you can pick migrating to a better supported doc flavor like TS, which is also hard. I personally think that the (hard!) migration to TS has a brighter future, so that's what I generally recommend, with the understanding that everybody's situation is different and it may not be the best fit for you. |
The main friction, as I see it, is that it's not a simple case of a docs migration. The docstrings in our code are (largely) already typescript compliant, but getting an infrastructure set up to actually build documentation HTML using Would be happy to be proven wrong, but this probably isn't the right place to dive into it. |
I agree this isn't the place, but https://github.com/TypeStrong/typedoc/issues looks pretty active -- 86 open out of ~1400 total, lots resolved within the last week, and the first "closed issues" page dates back about a month. I really, honestly don't want this whole thread to turn into JSDoc-bashing, but compare that with this repo, where the first page of closed issues goes back fully 2 years. I'll take working with a vibrant community to get through a painful initial setup over sticking with a stagnant project any day of the week. |
I would also opt for the merge and setting up typescript to emit types and declarations as also docs from pure JS is indeed the only thing that i do and it is not so hard anymore it has much improved but you need to learn tsconfig a bit. Just my 5centit makes not sense to maintain the old jsdoc type behavior it should algin with typescript. Anything else will have no future. |
Classes or constructor functions as either return types or function arguments are both common and idiomatic in JavaScript. |
@ferrao because the use case is not basic in JS/ECMAScript anything can be anything and anything is anything a more easy explainer would maybe be the JS Fundamental Design says everything in JS is a Object even a string "I am Object".toString() A Object is defined as a UTFString Indexed Object that can have nested Object eg: Methods Functions Symbols and now comes the horror a Object can return Anything so you Class can be Anything import EventEmitter from './EventEmitter.js'
const aha = class extends EventEmitter {
constructor() {
super();
return "Ups i Did it again"
}
}
new aha() === "Ups i Did it again" let me give you a example of a class that changes over time after lets say 2 process iterations it will get a property import EventEmitter from './EventEmitter.js'
const lazy = class extends EventEmitter {
constructor() {
super();
this.later = "Ups i Did it again"
setTimeout(()=> this.later = 5, 100)
}
}
const l = new lazy()
l.later === "Ups i Did it again"
setTimeout(()=>console.log(l.later), 300) // l.later === 5 |
maybe your all interrested into this https://github.com/tc39/proposal-type-annotations we are trying to get type annotations parsed as comments directly in ECMAScript it self 🍡 |
I’m rather surprised this is still an issue in 2023. Currently, it doesn’t seem possible to use JSDoc and have the TypeScript LSP understand when you’re referring to a class and when you’re referring to an instance. e.g., In a simplified example from my use case, where I need to provide type information for a global object, the only way I have found so far to do this is to provide separate types for the class and its instances. Needless to say, not a great solution and very confusing for those having to consume this during authoring: index.d.ts:declare class Session {
createdAt: Date
authenticated: boolean
hasExpired (): boolean
} globals.jsconst Session = /** @type {typeof import('./index.d.ts').Session } */ (globalThis.kitten.Session)
const SessionInstance = new Session()
// Have to use SessionInstance here
const _db = /** @type {{
sessions: Object.<string, SessionInstance>
}} */ (_kitten._db)
// And Session (the actual class) here.
const session = new Session() |
In case you want to use TypeScript syntax not supported by JSDoc, but still keep the ability to generate the docs without class Data {}
const data = new Data();
class View {
/**
* @param {Data} data
*/
constructor(data) {}
}
// using typeof
/** @ignore @typedef {typeof View} ViewClass */
/** @type {ViewClass} */
const viewClass = View;
const view = new viewClass(data);
// using new
/** @ignore @typedef {new (data: Data) => View} NewableView */
/** @type {NewableView} */
const newableView = View;
const anotherView = new newableView(data);
// in a function parameter
/**
* @param {ViewClass} view Class of {@link View} to create
* @param {Data} data
* @returns {View}
*/
function createView(view, data) {
return new view(data);
} this fixes VSCode (TypeScript) type checking AND you can still generate JSDoc fine (except for |
Right now I couldn't find a way to document that a function argument (a property, or anything really) is a class, or a constructor of a specific type.
Here's a condensed example of the problem:
How is it possible to tell that the type of
ViewClass
is a constructor/class and that it extends View?What should go in the place of the question marks up there?
@param {View} thing
this means thatthing
is aView
instance, not a class@param {Function<View>} thing
this doesn't really mean thatthing
is a class that extendsView
@param {typeof View} thing
logically this is what we're looking for, but frankly I've never seen this one used before, not in the docs at leastThe text was updated successfully, but these errors were encountered: