-
Notifications
You must be signed in to change notification settings - Fork 48
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
Types as comments without changing JavaScript syntax. #176
Comments
Normally what you've described above can be solved with the already existing JSDoc syntax. /** @type {(hello: string) => string} */
function greet(name) {
return ‘hi ‘ + name ;
}
/** @type {number[]} */
const arrayOfNumbers = []; |
I think you may have missed the purpose of this proposal? What you're describing already exists. This proposal isn't about adding type annotations to JavaScript; it's about not needing an extra compile step in the existing typed variations of JavaScript, and about not having to use JSDoc comments which are generally more tedious to read and write (and are thus less clean and simple). |
... in a sad state. Can't remember when it was last updated and it still has the syntax of a JavaDoc that was there as a complement to an existing static type system. Or, if it exists, can't it also be an argument against this entire proposal? "JSDoc exists, we don't need this proposal" kind of thing? Would be nice to have something more powerful, but away from the existing JS syntax. A clean separation is even easier on the eyes, less clutter in that one line where you define a function, its type and what else... annotations one day? JSDoc are tedious because their syntax is not that good, and hasn't been updated much these last years, so it has nothing to do with them being separate from the actual function. |
Oh, I forgot
What I suggested is in line with this above, you can have your single compile step read the comments AND code, right? We can add that to the language itself, be it a
Yes, it is, hence my comment about not doing it as proposed, but a bit different, like I originally posted:
Just to be clear, I don't consider Flow or TypeScript as JavaScript. They're separeate languages, thus, there aren't "existing typed variations of JavaScript", there are only two variations: strict mode and non-strict mode. |
I think this is the source of your confusion: When I said this proposal isn't about adding type annotations to JS, I meant this proposal's benefit isn't merely that JS gets type annotations. The proposed benefits I referred to were TS syntax not requiring a compile step, and people who prefer TS syntax over JSDoc being able to use that with less friction. Your suggested alternative seems to miss the point because it doesn't substitute a solution for these problems of friction. Instead, it substitutes the addition of type annotations, despite that JS missing type annotations isn't the underlying problem this proposal is trying to solve.
No, in an identical state. Your suggestion is just to use comments, which doesn't need a new ECMAScript proposal in order to be valid JS, because it's already valid JS. This proposal is for changing the language and its syntax. If you just want to use existing JS syntax, then you can do that today, and this proposal is not for you. As I already said, this proposal is for people who want convenient type annotations supported by their IDE while avoiding using JSDoc or adding a compile step to their JS project.
I don't think you've made any such argument? An argument against this proposal would involve justifying that the detriment of this feature outweighs the benefits it provides, such as removing a compile step for type annotations in some situations. I'd understand if you were arguing benefits like that are outweighed, but that doesn't seem to be the case. |
@GrantGryczan it would still require a compile step unless the entirety of TypeScript was contained in the proposal, which isn’t the plan as i understand it. |
I think what would be likely to happen is that there would be a use "TS in JS" flag for projects using typescript checker on JS files with this proposal, the editor would ensure you are writing files which conform to the spec and like with JSDoc support new TS syntax features might take a bit of coercing to fit that space. Overall though, I'd expect the amount of TS-in-JS files to eat into "plain 'ole .ts" files/projects to the point where most people are writing the TS-in-JS and that the lack of a compile step is a strong pull for that |
If this proposal is accepted, I wonder how all the tools in the JS ecosystem would change as a result. For example some projects may not have 🤔 Also, I wonder if some typescript-eslint rules would make their way to eslint as a result. |
Any JavaScript tool like eslint would know how to skip over the code which defines types, as defining that behavior would be a part of the spec. It would allow the same tools to work for more than just TypeScript for example, as other type system can fit into the space If you have code like |
@ljharb I didn't mean using TS features this proposal doesn't support. For people only using supported features (which most of the features are), a compile step would be eliminated. Or, to put it differently, for people using vanilla JS (especially Node.js where there often isn't already a compile step for minification) who would benefit from type annotation, it would make introducing types to their codebase more accessible due to the reduced friction, especially for those who prefer TS syntax over JSDoc (which, judging by their popularity, is most people). Also, I'm not sure why you're saying a compile step would necessarily be required, considering reducing the need for a compile step is brought up by the proposal itself multiple times? That's why I commented about it in the first place. To quote it (regarding two different use cases):
|
I don’t personally think there’s much value in making things more complex by saying that some, but not all, TS users can avoid transpiling. |
I'm not here to argue whether there's value in it, I'm just clarifying one of the points the proposal makes since this issue doesn't seem to attempt to solve the same problems the proposal is attempting to solve, or at least attempt to solve some of the problems with a better trade-off. This issue only suggests a new format for type annotations as comments--so not something that could be a TC39 proposal since comments are already valid JS, just as JSDoc also didn't require a TC39 proposal. |
Correct me if I am wrong, but the scope of tc39 is[link]:
Static typing is a complementary technology that supports the EcmaScript language. A static type system needs specification to be defined, regardless of whether it reserves syntax inside native comments. I would like the opinion of @ljharb on this one. |
I hadn't personally seen any instance of TC39 handling anything besides ECMAScript semantics and syntax, so I was under the impression this didn't fall under its scope, but if it actually does, then that's reasonable! I thought it would be something the community would be better off handling like TypeScript, Flow, JSDoc, etc. But either way, I still don't think this suggestion attempts to solve the same problems this proposal does. You may disregard the sentence of my previous comment about TC39's scope. |
Be more specific please. |
I've already argued that statement specifically in most of my previous comments, so I don't think continuing to repeat myself or participate in this conversation will really help anyone. If my first few comments didn't get my point across, it doesn't seem any further comments will (at least in a reasonable amount of time). Sorry to end the discussion abruptly. |
Please read the tc39 meeting notes [1][2][3][4]. The context proposal has yet to provide a syntax that is working. The assumption that the context proposal will support, all or some of the already existing TS syntax, has no proof. Also there are no restrictions to the solution scope in stage 1 proposals. What the op suggests, and any other suggestion that does not need to introduce new "comments", solves the problem statement, and despite how much people do not want to admit it, this is done without the drawbacks of the context proposal. To make matters worse the problem statement is already solved without the need for any kind of tc39 proposal. Take a look for example how SvelteKit and Deno used TypeScript without the need to compile: Have you actually created projects like this? I personally have. Most people have not, and that makes them believe that we need the context proposal. Finally this:
mentioned in tc39 meeting notes, is nothing more than an artificial problem created by the intrinsic drawbacks of supersets: arbitrarily reserving syntax without tc39 approval. You simply stop using supersets, and move to complements, and the problem is solved. It is my opinion that tc39 should strive for people to stop using supersets, since this will lead to a healthier ecosystem. In the end the fact that people seem to not really know what is going on with the context proposal, hence countless issues like this context, is because, the maintainers of the context repo do not seem to be bothered to just add links to the tc39 meeting notes in top of the |
@GrantGryczan there is no confusion. You're proposing syntactic change to one language for the benefit of another language. TC39 should change syntax for the purpose of the EcmaScript language. That is all. My suggestion was to evolve the ECMAScript language (or at least the practice of it) in a way that:
I think @lillallol threaded the similar line with the problems of supersets, and what I consider "muddying the waters" by considering other languages as JS-but-* (better, different, etc). They aren't it, so any proposal for a complementary technology should be part of a complementary technology technical committee, and any proposal to TC39 should be about the benefit to EcmaScript, not other languages. |
You've used these projects a few times as examples for why you don't need Typescript or typescript-like type annotations. Have the maintainers weighed in on this proposal anywhere? Especially for SvelteKit, where they seemed most interested in removing a compile step, I wonder if they considered JSDoc to be the best, or the best currently available, and if they would have considered some of the proposed syntax of this proposal to be a better choice. |
To be honest I use these projects as examples because:
I do not need them as a proof for what I claim. My projects are enough.
As far as I know, no. Why are you making this question? That is a strange question. It seems to me, like a question that would come from someone who have not used TypeScript the way these projects do. Have you actually used TypeScript like these projects do? There is no going back when you are appropriately exposed to this way. It is simply better.
Lets be clear here. TypeScript type checking is needed. I would never use JSDoc on its own without TypeScript. I personally use TypeScript in all of my projects regardless the size. I just do not use TypeScript as a superset. I write strictly all types in
Native supersets are currently not working. There is no working syntax provided by the context proposal, hence it makes no sense to ask them whether they have considered it, since we might end up with a completely different syntax from the current one. For the case a working syntax is found that is accepted by all of the tc39 members (when? next year? next decade?), then all the pros and cons should be considered. For example it makes no sense to just compare syntax when breaking changes (like nothing of TypeScript is valid syntax) are introduced to all supersets + and the JS parser becomes slower regardless of the usage of the new syntax. |
@lillallol TBH I'm not going to do much back and forth and respond to each piece, as I feel like anything further would bloat the comments without adding much value. But to respond to you asking why I was curious about the opinion of those projects' maintainers: I assumed you were using those projects as proof that your arguments are valid. With that assumption, it seemed to me that the opinion of maintainers of these large, popular projects would be valuable, and that the continued usage of them as proof would be unfairly putting words in their mouths. Also, your success with using declarations and importing them with JSDoc comments in private projects might be proof enough to you, but I'm sure you can understand why it might not be convincing to me or others you've debated with. You are correct that I haven't used types in this way. But for smaller projects, I have actually considered dropping TS and writing JS with declaration files, because, as I've said in a few other places, I'm more interested in using types to communicate intent than to be strictly asserted. So perhaps I will someday. This may not be the most compelling reason, but I do find a TS-like (or Python-like) type annotation to be the easiest way to write intended types, hence my interest in this proposal. |
I do not understand. Be more specific please. |
Hard disagree about the "simply better" part. Am "appropriately exposed" to TypeScript. It sucks and is user-hostile. Fight me. The "no going back"... jury's still out on this one. Either there is a going back (to JavaScript as a scripting language, without bundlers, preprocessors, compilers being a mandatory part of the toolchain), or, thanks to WASM, there's a going to a different language 🤷 |
JavaScript always had |
That's not in question. The thing is, how? There are many questions connected to it:
With comments, you can have flexibility and freedom to extend with different solutions without spending years disussing it in a technical comitee that has to be concerned that what you add to the standard is hard to remove least you break the Web. Otherwise, here is one version that doesn't require you to re-invent syntax so you will be able to shoehorn it in every place imaginable:
This last block (the shoehorned part) is contrary to the separation of concerns I would like to have and to think will be useful as to allow more freedom for newer and better ways to express and check the types |
@azder This kind of dovetails with a thought I had when discussing Even in combination: Example (not with types but it would work the same): If currently you can do: // impl.js
export function foo (a, b) { return a + b }
export const bar = 1 // index.js
import * as Impl from './impl.js'
import * as assert from 'node:assert'
assert(Impl instanceof Module) // import "returns" Module
export function fooBar (baz) {
return Impl.foo(Impl.bar, baz)
} The import * as assert from 'node:assert'
assert(Impl instanceof Module) // hoisting like functions
export function fooBar (baz) {
return Impl.foo(Impl.bar, baz)
}
// create Module in place, automaticalyl enclosing a namespace
package Impl {
// parent scope is not visible here
export function foo (a, b) { return a + b }
export const bar = 1
} This would do native namespacing for both types and values. And then it could also be used to denote code that is governed by an external compiler, e.g. import * as assert from 'node:assert'
assert(Impl instanceof Module)
export function fooBar (baz) {
return Impl.foo(Impl.BAR, baz)
}
package Impl {
export const BAR = 1
export function foo (a, b) { return a + b }
}
export interface package ("typescript@5.2.2") {
export function fooBar (baz: number)
} |
This scares me 🤣. The result of Not sure about the rest of the discussion, need to read through. 🌷 |
@trusktr please note, I don't use It's only meant to signal your pre-processor that it's not a regular comment, but something your DSL can work with. So basically Which is why in this example #192 (comment) I used |
Just to clarify intent, when you have something like this:
How exactly is this being parsed? Is the type-system tag What about the body of the interface. Is this behaving:
Option 1 is similar to what the proposal currently does in some places, and it means this: // Valid
// The inner curly brackets match up and get ignored.
// The `{` inside the string is not treated as an inner curly bracket
// since we have enough context to understand that that's
// supposed to be thought of as a string.
interface ('TypeScript','5.2.2') {
type ObjType = {
readonly value: '{'
};
}
// Invalid
// there's not a closing quote to match the opening quote
// Not all languages things of single quotes as strings,
// e.g. the ML family of languages allow you to put
// one single quote next to a type name.
interface ('TypeScript','5.2.2') {
type ObjType = {
readonly value: 'a
}
} Option 2: // Invalid
// There are more opening brackets than
// closing brackets, so it's going to try
// to parse whatever comes after this
// as part of the comment as well.
interface ('TypeScript','5.2.2') {
type ObjType = {
readonly value: '{'
};
}
// Valid
// Since we're night trying to tokenize the contents,
// we can invent new uses for single quotes and what-not
// beyond "a single quote is a string".
interface ('TypeScript','5.2.2') {
type ObjType = {
readonly value: 'a
}
} |
@theScottyJam First, the very simlpe short answers:
The following should not cause JS to throw an error, but JS could backtrack and pick the final
In a happy scenario, JS would be ignorant of anything inside the block, skip it, not parse it at all, which is why I mostly prefer using comments, so as to not be changing the language syntax, and especially semantics. The original comment with that specific syntax was more like a spur of the moment exploration. Further down I've reconsidered, maybe re-using the existing
The extra tokens are supposed to serve whichever parser is dealing with whichever DSL is being imported. As I've imagined someone might figure out how to use This way people can have all the extra semantics they need, but also not baking it into JS, thus leaving the language as a common denominator for different type checking DSL's without JS being expanded. And if serving files in this manner is a good start, maybe there will be a possibility of using a reserved keyword. At the very least, comments like |
For sure. Yeah in my examples I was using it as a type for the thing the comment is associated with, rather than definitions. It needs bike shedding |
And that's precisely what I want to avoid. That makes these kind of comments context sensitive and forces (as in soft power) or enables (as in abusive, not empowering) people to mix declaration and implementation in the same place. |
If we could just agree on a format, then all editors can support this. Typescript needs to die asap. |
That's what I prefer personally though. I like TypeScript's inline annotations, and personally I would like comments to be similar. The best solution would allow both forms, so people can choose. |
As someone who often uses Python, Python's ability to easily "throw in" a type inline has been a lifesaver for improving the editor's suggestions. For example, Django's ORM adds dynamically named methods and attributes, which a type checker can be unable to follow. For example: class Foo(models.Model):
# this FK adds the `foo_set` attribute to MyModel
my_model = models.ForeignKey("MyModel", on_delete=models.CASCADE)
# foo has an Any type because foo_set is a dynamically named attribute and not
# part of the class definition. Because of this we don't get good suggestions
# from the editor.
foo = my_model_instance.foo_set.get(pk=1)
# now we get appropriate suggestions.
foo: Foo = my_model_instance.foo_set.get(pk=1) I believe that, for JS, it can be just as helpful to be able to add an inline type with the implementation. I can currently add in a type with JSDoc comments, but honestly (I might sound pretty lazy for saying this) writing out Edit: Also, being able to write out types inline with the implementation makes it easy to write "incomplete" type definitions without repeating oneself, where you don't need every type to be defined. For example: // I, the writer, don't really care about what type `maybeNull` is,
// and the return type (void) can be derived from the function body,
// so it can be cumbersome to write out more than is necessary for documentation
// or helpful editor suggestions.
function assertIsNull(maybeNull, message: string) {
// ...
} |
You missed to quote the important part @trusktr @spenserblack
If you give people the ability, they will abuse it. Some examples of giving giving people the choice in the past caused fights (more like waste time and energy):
This second one is particularly dangerous in JS because people will treat it as a stylistic choice in a language that does ASI and can alter the meaning of the code (that one example of Everything that can be solved with an inline comment could be solved with a comment in the previous line. @spenserblack as someone coming from the viewpoint of Python, I think you'd appreciate the principle of having only one way to do something. @trusktr I am usually all for having more options (as I have shown above trying to figure out different extensions to types for JS), but in this particular case, I'm sure if you give people the possibility to write something like TS, they will write it like TS - all in one place, no separation of concerns, no separation of domains (code vs meta-code), even though in TS they also have the ability to separate much of the types outside type Fn = (a:number, b:number) => number;
const fn: Fn = (a,b) => a + b; and yet, people will often do function fn(a:number, b:number) :number {
return a + b;
} because it's how they are used to i.e. "this is how I like it" |
TypeScript the project is pretty much died at this point; Deno, Bun, Node.js (--loader), esbuild, swc, oxc, etc..., more to come to digest the pie. User should not cares about types, if JSDoc and LSP (Linter, Checker) serves better role, plain JavaScript would just be fine. In Haskell you write ONE line annotation on top and it derives into dozens of solid sound code, you could even skip the annotation and just ask the compiler: What type should I put there? What's the point of reinvent |
const num = 42; // this is javascript
const num: number = 42; // this is typescript day 1
const num: 42 = 42; // this is typescript day 2
const num = 42 as const; // this is typescript day 3
// this is typescript today, can you spot the difference between javascript?
const num = 42; |
@imcotton what are you even trying to say here? |
Not exactly. TypeScript can never infer the exact type you want 100% of the time. Not matter how advanced it can become or with the help of AI. It is physically impossible to do that. |
Focusing solely on improving type inference seems too demanding. Personally, I'm not opposed to shifting heavy lifting into TypeScript itself still lacks essential type features like curried generics and HKTs, I wouldn't expect 100% accuracy anytime soon, let alone any proposal lacking specificity and capability may as well not achieve this goal too. Even if such a proposal were adopted in the future, the benefits might not justify the effort, given TypeScript's current capabilities and the future development, which have grown tremendously over the years. It would be disappointing if, in the future, TypeScript users effortlessly wrote inference-heavy code like JavaScript, while those using this proposal struggled with verbose and less expressive syntax (also not JavaScript). Overall, while the proposal has its strengths, it may not fully meet market demands. To echo from beginning of this issue, even as alternative, adopting Haskell's Hindley-Milner type system could offer a robust solution. It promises compatibility with existing code (only annotations in comment), reduces TypeScript's technical debt, and leverages Haskell's proven type system, might also including dependent types (one can dream), what else do we need? |
I guess, AI/LLM is out of scope here to make decisions based on them, as they are not a native part of the JavaScript ecosystem and shouldn't become one. It's separate technology and everyone can choose to use or not to use it, so it doesn't make sense to include them in this discussion. |
you're asking for static types. that is fundamentally NOT what javascript is. JS is inherently dynamic and changing that would require a different language all together. the closes you will get with this is the this proposal is simply to get TS syntax to be compatible with JS so that transpilation is no longer required. browsers and servers should be able to operate on TS directly without having to strip out types before running the code. This is more in line with the |
No, the case were specify selected because it is part of ECMAScript spec1. From es2015.core.d.ts2:
Footnotes |
There are on going proposals: |
Can you elaborate on how what you are saying contradicts my statement? |
I see, my apologies for the confusion. I saw "they are not" as thinking you meant "they" as The reason for pulling AI/LLM here is to avoid relying totally on TypeScript's schedule or priorities, recognizing that AI/LLM has its own focused aiming to assist users. |
You can have it today, for not extra price and for a lot cleaner code.
Types as comments should work similar to how JSDoc doesn’t need to change the syntax of JS and how Haskell doesn’t need to mix type declaration with the definition, but adds it just before it, with good compilers if you really need it since inferencing will do most of the work.
This is comments as types
You can change the comment syntax a bit, like
or
or whatever else you like.
Just keep it clean and simple please, and most importantly, out of the definitions we already have in the language. Type information can just be added besides them
The text was updated successfully, but these errors were encountered: