Description
Suggestion
In TypeScript's documentation of classes, it says:
In this example, we perhaps expected that s’s type would be influenced by the name: string parameter of check. It is not - implements clauses don’t change how the class body is checked or its type inferred.
I discovered while trying to type a .js
class with @implements
that while I thought the issue was with the JSDoc keyword, the issue is with implements
itself. There is currently no way to implicitly type the methods of a class with a single definition. This would be IMO a great feature for TypeScript, especially as some libs move to lean more on JSDoc.
🔍 Search Terms
@implements
implements
✅ Viability Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.
⭐ Suggestion
Allow implicit typing of the methods of a class from one place
📃 Motivating Example
So, take this example:
export interface Print {
prototype: {
print(txt: string): void;
}
}
/** @class */
export const TextBook: Print = function() {}
TextBook.prototype.print = function(txt) {}
You'll note if you type-check this code that txt
does not need explicit typing. However, AFAICT, there's no way to type a class this way in TypeScript. Meaning that classes actually have less TypeScript support (in this instance) then the traditional JavaScript pattern that class syntax often replaces.
In fact, as noted in the above documentation, TypeScript specifically does not provide this functionality even while noting that developers might expect this to be supported in some way (if only because the prototype
syntax is supported).
In other words, there is no way to type the print
method here using an external class, which makes type-checking a .js
file with JSDoc more difficult than its .prototype.
equivalent, or making a single type for a class nearly impossible. As in:
export const TextBook2: Print = class {
print(txt) {}. // the type of `txt` will not be inferred
}
Note also that using .prototype.
allows us to check for exact types and excess properties, whereas the class pattern offers no equivalent:
Again, this infers that TypeScript currently has no way to accurately describe the shape of a class externally, even though this seems to available for all other primitives and built-in objects.
💻 Use Cases
I'd like to be able to describe a class using a single JSDoc @type
import, or, similarly, use a declaration like const Foo: MyClass = class {}
to correctly type all properties, methods, and the constructor. This would maintain parity with what a developer can do right now in TypeScript with function prototypes.
Possible workaround
If, for some reason, there's some syntactic reasoning behind not fully supporting class types, it would be great if we could somehow tell TypeScript to support a type shape by describing it's constructor / prototype without actually using classic function prototypes. In other words, do what TypeScript can already do right now with Function.prototype
, but apply it to the class syntax.