Open msadeqhe opened 1 year ago
package
I'd like to add another previously reserved keyword, package
, to the list of existing things which could be put to use for the type syntax.
package
could be used to define type namespaces, write ES modules inline, delineate subsections to be delegated to a specific compiler (be it TS, Flow, JSX...) - somewhat equivalent to mod
in Rust. Example on https://github.com/tc39/proposal-type-annotations/issues/176#issuecomment-1732415685
It may seem like I'm focusing on the negatives.
I'm just trying to consider a class of people who don't want or can't use static types annotations for reasons. Howwill they can continue using JS without or with less friction? E.g. how would they need to adjust code they've imported or copied? Would it be easy to focus on implementation if tag soup is inlined or pre-lined (like JSDoc)?
In short summary:
1.interface
keyword - 👎 see a)
?.
- 👎 tag soup inlined b), but also more overloaded meaning of the character sequence ?:
!.
- 👎 not complementary to ?.
see c)<>
- 👎 is awful looking syntax we can't escape from due to inertia, so only b) is an objectionpackage
- 👎 see a)a) The TL;DR: that Jurassic Park quote "preocupied with could, didn't think if should". But, even if we use it, should it be in the same way it was used in other languages? I've talked about sedimentation a bit here https://github.com/tc39/proposal-type-annotations/issues/176#issuecomment-1732518449
b) Inlined tag soups are something that would add more problems for dealing with edge cases in the EcmaScript syntax and still potentially limit how another typing language can be inserted. Think of how RegExp is a language you can use in many places, but with not having it being defined as to what syntax it has, but be open to many different ones in the future.
Also, separation of concerns. I'd think the concern of specifying types should not be mixed up in the same place with the concern of implementation. Think haskellian, two lines instead of one:
identityFunction :: Type -> Type -- type info is separate from implementation detail, different block, file, different syntaxes
identityFunction x = x -- the implemenation detail will remain the same, no new syntax headaches
c)
The thing about ?.
is that it is a runtime operator, not a compile time type assertion. So, they aren't complementary.
With regard to run time, !.
in EcmaScript already exists as .
and []
- both of which will throw a TypeError
if you try to access a property on null
or undefined
value. In code this is not necessary because you can just use the (6a) networking truth and add a function.
E.g. if I want to have a safe default, I'd use
const asString = $ => null === $ || undefined === $ ? '' : $; // write once
const email = asString(inputEmail).toLowerCase(); // use everywhere
With regard to compile time, same argument as b)
The simpler reason why interface
or package
wouldn't fly, elegant as reusing some of those old reserved keywords might seem, is that runtimes generally don't expect them to be keywords and treat them as identifiers. So, still a breaking change in the language.
I'm reminded of "use strict"
(and current incarnations like "use server"
) as examples of other ways to upgrade JS in an at least somewhat backwards-compatible way. But AFAIK that changed semantics, not syntax - strict mode programs would be valid on a pre-strict runtime, only incorrect?
So far comment-based approaches remain the only ones which solve for backwards compatibility and for truly optional adoption.
Let's find out which part of TypeScript, Flow, etc can be a part of JavaScript without type annotations. Which features of TypeScript, Flow, etc can be used without radically changing the syntax of JavaScript?
1. Interfaces have their spot in JavaScript.
It's reasonable to have
interface
language construct in JavaScript, because it's not necessary restricted to type checkers! in a way that aninterface
can be declared without any type annotation. That's it. Interfaces are somehow abstract classes, and they can be used to help us to declare other classes. On the other hand, we needimplements
keyword to implement interfaces within classes. Fortunately bothinterface
andimplements
have been reserved keywords in JavaScript for the future use, so there will not be any source compatibility issue at all. For example:Also with the native support from JavaScript (not as comment), we may
import
andexport
interfaces similar to classes.2. Optional arguments and properties with
?:
syntaxBoth of them can be safely ignored even without type annotations:
EDIT: Ternary operators cannot be in argument list of function declarations. So
arg?
doesn't break any JavaScript program.3. Non-nullable assertions with
!.
operatorIt's complementary to
?.
operator:4. Generic argument list
The
<
and>
operators are not allowed in class, function and variable declarations. So JavaScript can treat them as comment instead of reporting a syntax error:Which features from TypeScript, Flow, etc are too much related to type annotations?
type
(in TypeScript, Flow, etc) andopaque type
(in Flow) features are definitely too much related to type annotations.satisfies
andas
features in TypeScript, should be treated as:
-style comments, because they are extensively related to types. Respectively their syntax can be changed to:(EXPR: satisfies TYPE)
(EXPR: as TYPE)
In this way, both
satisfies
andas
are not necessary to be keywords. JavaScript syntax should not be changed as much as possible. New keywords may make some existing programs to break.And any other part of the syntax from TypeScript, Flow, etc which are for type annotations, should be changed to
:comment
syntax in JavaScript (with simple rules as much as possible).