Open corevo opened 2 years ago
It might be worth re-reading the spec/minisite: https://giltayar.github.io/proposal-types-as-comments/ as this proposal is about declaring areas of syntax which JavaScript does not do anything with (aka 'treat it as comments') and not about standardizing a type system into JS.
Issue 1: TypeScript generational improvements (expectation of future compatibility)
This would be handled by TypeScript knowing that you are in a JS file and raising an error for users (when using something like enums for example) - it's likely that enums or something like it may find its way into the language (which has a TypeScript team member on the champions) - at which point it would be native to JS.
Issue 2: Use of new reserved words
Declaring new keywords or syntax is always a breaking change, and backwards compatibility is usually handled via tools like babel / TypeScript to declare which version of JS you support (e.g. es6/es2015)
TypeScript's syntax would also shift somewhat to support this proposal, as it's not 'take TypeScript and make it JavaScript' but that work should be worth it for long-term alignment between JS and JS + types.
Hi @corevo
For example, this proposal excludes enums and namespaces, to the typescript user it'll be unclear wether a certain feature will exist only in typescript or wether it is worth the wait to see if that feature gets standardized as a "comment".
The reason enums and namespaces are not included in this proposal is because they can’t be treated as a comment, as they have runtime semantics. Some TypeScript developers already avoid these parts of TS because of this and use alternative patterns. That said there are separate proposals for adding enums to EcmaScript which could progress separately.
@orta I understand the part where the type annotations are ignored by the interpreter and compiler. I might have to re-iterate my point since I see others misunderstanding what I was trying to convey.
The point of this proposal is for me to be able to use tsserver
without needing to write typescript and subsequently compile it using tsc
.
The issue I laid out is for the end user, he still needs to install the typescript LSP in order to get the value out of these "comments", thus causing a confusion for the end user, on the one hand he's writing javascript, on the other he's using tsserver
to get static analysis.
This in turn can cause the expectation of javascript to become typescript.
@acutmore you allude to my point, typescript could change it's syntax from type
to something that will be backwards compatible with javascript, but regardless of what typescript chooses to do, this proposal has to be updated first to be backwards compatible.
Hi @corevo
@acutmore you allude to my point, typescript could change it's syntax from type to something that will be backwards compatible with javascript, but regardless of what typescript chooses to do, this proposal has to be updated first to be backwards compatible.
Would you be able to expand on what you mean by saying that this proposal should be backwards compatible? Most TC39 proposals are only forwards compatible (existing programs will continue to function unchanged when executed by newer engines) but are not backwards compatible (the new syntax will result in an error if used in an older engine).
Adding type
as a reserve word will break existing javascript programs, in ES2022 this is valid JavaScript
const type = 5
The proposal seeks to make type
a reserved word, rendering this program illegal.
A workaround would be to find alternative syntax to typescript's type aliases using existing reserved words, another solution would be adding a new mode, but TC39 were pretty clear on not doing that.
I'll expose my ignorance here, but is the way in which a reserved word is used a sufficient distinction to make this less of an issue?
Consider:
const type = 5 // valid JavaScript
type NameOfType = { some type: string }
In the second case, type
is always used in the context of being at the start of a statement and always followed by an identifier. As opposed to the first where type
is a variable identifier (words may be wrong here)
Does that distinction allow this to be "less breaking" from a parsing perspective? Appreciate that the whole proposal is about introducing new syntax anyway, just kind of interested in the nuance here
@johnnyreilly the compiler won't know in line 2, wether you are referring to the identifier type
or to the reserved word type
.
Also usually reserved words are checked first in the tokenizer, we'll have to consult someone from V8 to get input on this issue, but in any case consider this:
'use strict'
const interface = 5
Will fail parsing because interface
is a reserved word, so even if it was possible lexically (which I'm not an expert on), it would change the current behavior of the language, currently the language restricts reserved words from being used as identifiers.
Another issue that I didn't get into in this thread is the reserved word interface
, it is already reserved in strict mode, and it is unclear wether TC39 will use it as a comment, they might reject the proposal on grounds that this word is reserved for logical use.
Just want to point out that
const type = 5
is valid TypeScript (4.6.2), so a parser should be able to handle this even if type
becomes a keyword.
In fact,
type type = 5;
const type: type = 5;
seems valid. https://www.typescriptlang.org/play?#code/C4TwDgpgBKlQvFArAbgFAGMD2A7AzsDOBAFxFyKpA
Other reserved keywords (interface
, as pointed out) seem invalid, though.
@jasikpark The fact that this is valid typescript does not make it necessarily valid javascript, looking at my first point, I was afraid of the expectation of this proposal becoming "standardize typescript into ecmascript".
According to the language rules, a reserved word can't be used as identifier, this is not true for typescript (since it has to be a superset and type
is a valid identifier), but the fact that it is valid typescript does not mean it should also be valid in javascript.
@corevo I'm going to guess that you meant to tag me :laughing:
According to the language rules, a reserved word can't be used as identifier, this is not true for typescript
Thanks for explaining! I wasn't aware that that was a language rule of JavaScript (I should have read your comment more thoroughly). Now I understand the concern much better. In that case, assuming that language rule doesn't change, I share your concern. In fact, I think that const type
could actually be very common.
It's generally true that reserved words can't be used as identifiers, but for reserved words that haven't been reserved since the beginning of the language, the language grammar makes them "conditionally reserved". This is the case for await
and yield
which are sometimes allowed as identifiers. There are also keywords that are not reserved, such as async
, which is always allowed as an identifier despite having a syntactical meaning in other contexts where identifiers aren't legal. So I'm not sure that concern about language rules is entirely accurate. The section Keywords and Reserved Words explains more.
Basically, it's entirely up to the grammar what the rules are for when you can use an identifier. If you want to allow only names that are not keywords, use Identifier
, if you want to allow any name, BindingName
(iirc), if you want it to be permitted in some contexts, and not others, use production parameters, e.g. await
is permitted as an identifier (grammatically) if and only if the [Async]
parameter is false, which is true in async
functions and generators, and false otherwise. (Although it's actually made illegal to use await
and yield
as identifiers in strict mode with a semantic rule)
There is also the case of async function ...
, where async
is not a reserved word (and thus is a valid Identifier
), but is treated as a keyword in that specific production.
An interesting case is in object literals, where you can use async
, get
and set
as property names, just like any other keyword, but you can also use them as keywords, like in { async foo() { ... }, ... }
.
So yeah, the ship sailed a long time ago on being particularly dogmatic on keywords. Good riddance, they are pretty useless, really.
The issue I laid out is for the end user, he still needs to install the typescript LSP in order to get the value out of these "comments", thus causing a confusion for the end user, on the one hand he's writing javascript, on the other he's using tsserver to get static analysis.
I get the point, and it has some merit to it. But this is true for JSDoc typings too, and yet the people that use them don't get confused. Another data point is Python types, which are very similar to the proposal here (and were an inspiration for it).
JavaScript still has some cases of ambiguity with keywords. As @simonbuchan mentioned above, async
isn't a reserved word in strict mode or in "sloppy mode". If anyone needs another example, let
isn't a keyword in sloppy mode environments, so this code is valid JavaScript (as long as it's not in strict mode):
var let = 23;
let result = let + 45; // 68
let; // 23
let let = 45; // this is not allowed
Disclaimer: let
isn't allowed to be declared using let
or const
statements to prevent ambiguity there.
First off I think there is some preface I have to explain, typescript has two parts to it
tsc
the process of transpiling typescript down into javascript and declaration files.tsserver
the static analyzer that gives the developers the hints and refactoring tools in their editors.The gist of the proposal is to allow use-cases where
tsc
is not needed for certain files, which means that they will not need to depend on typescript at all, so long as the user hastsserver
or another static analyzer installed on his machine that is able to consume these annotations.This approach creates two issues, both of which can be resolved, but I was wondering what is the proposal plans on solving them.
Issue 1: TypeScript generational improvements (expectation of future compatibility)
Just like with ecmascript, typescript gets generational improvements as well, except this time it is unclear wether it'll make it into ecmascript or not.
For example, this proposal excludes
enums
andnamespaces
, to the typescript user it'll be unclear wether a certain feature will exist only in typescript or wether it is worth the wait to see if that feature gets standardized as a "comment".An obvious answer to this concern is to say, these features (type annotations, interfaces, type aliases, etc...), are part of ecmascript now, and the rest aren't (like pending proposals), and that users should refrain or use their own judgement. But since this proposal draws so much from typescript, my concern is that it'll develop the expectation of compatibility.
Issue 2: Use of new reserved words
In order for this proposal to work in a meaningful way (as in to allow users to not use
tsc
), it'll have to declare new reserved words in the language, at minimum beingtype
.Given that TC39 is unwilling to create new modes for ecmascript (
await
is reserved only in modules), how does the proposal handle this backwards incompatibility?Without a new mode the interpreter won't be able to tell wether
type
should be reserved or not.One possible workaround is to break typescript compatibility, and to use existing language features to support it,
tsc
can then compile into that standard to leverage it's existence while staying backwards compatible syntax-wise.Summary
I think that my main concern is that this proposal draws so much from typescript, that it'll create the expectation of ecmascript being fully compatible with typescript.
But all of these are concerns of human behavior, so I digress.