JavaScript type syntax proposal separates parsing from checking
A Stage 0 proposal would let JavaScript accept erasable type syntax. Engines would ignore the annotations while external checkers retain responsibility for their meaning.
A build step that once handled browser compatibility can become unnecessary for everything except removing type annotations. That is the development-workflow problem behind the proposal Microsoft supported on March 9. It would let JavaScript engines accept certain type syntax and ignore it, allowing an external checker to keep interpreting the same source.
The announcement describes a Stage 0 proposal, with a plan to present it to TC39 for Stage 1 later in the month. It does not announce standardized syntax or browser support. The distinction matters because the proposal asks the language to reserve grammar for information that has no runtime effect.
I am wary of TypeScript's complexity while valuing what its tools make possible for web applications. This proposal interests me because it separates two responsibilities that development tools often bundle together. Running a program and checking its declared types need not require the same component or occur at the same time.
Existing comments already demonstrate the separation
The announcement starts with JSDoc annotations in ordinary JavaScript. Editors can use those comments for completion and refactoring, and TypeScript can check the file when requested. The JavaScript engine still treats the annotations as comments. That establishes a working example of useful type information without runtime type enforcement.
The inconvenience is syntax and expressiveness. A function's parameter types can require a block of comments separate from the parameter list. Direct annotations put the information beside the relevant binding. The proposal seeks that convenience while retaining the same separation between checking and execution.
The proposal as it stood on March 9 calls itself Types as Comments and explicitly labels the design a strawperson. It aims for a substantial subset of TypeScript and other typed JavaScript supersets. Its status is still Stage 0 and not yet presented to the committee.
That historical text is useful because it shows which questions remain open. The purpose is more settled than the grammar. Engines would recognize positions containing erasable information, while tools could apply their own rules to the contents. Agreeing on those positions does not require agreeing on one universal type system.
An annotation would not enforce its claim
The proposal gives an example of a variable annotated as a string and later assigned a number. A checker could report an error, but a conforming engine would execute both assignments. The annotation does not add a runtime validation operation.
let name: string
name = "service"
name = 100
Under the proposed execution model, the final assignment would still assign the number. This example describes proposed semantics, not syntax that ordinary JavaScript runtimes accept today. TypeScript would diagnose the incompatible assignment when checking the program.
The same separation applies to function parameters and return annotations. A declared numeric parameter would not make the engine reject a string argument. A type assertion would not inspect an object or convert it into a different representation. Those constructs would supply information to tools while execution follows the underlying JavaScript operations.
That is also why external input still needs runtime validation. A declaration about the shape of parsed data cannot establish that the data actually has that shape. The proposal preserves the existing distinction between a static model and an operation that checks a value during execution.
This model leaves room for different checkers. TypeScript and Flow can use the reserved syntax without requiring the engine to select one analysis as authoritative. A program can contain an annotation that an engine ignores and a particular checker rejects. The rejection belongs to the development tool's policy.
Editors could continue providing immediate diagnostics, and a project could still require a checker in continuous integration. Direct execution would remove the erasure dependency from that workflow without removing the project's chosen requirement that checked source pass before delivery.
Standardizing checking would change compatibility
The proposal's rationale explains why building a checker into every engine would be a different undertaking. A checker can discover more errors as its analysis improves. Developers can choose when to adopt a compiler update and repair the new diagnostics. An engine update that rejected previously running programs would impose that decision on application users.
The proposed grammar boundary avoids that dependency. A checker can become stricter without turning a browser's execution of the same source into a type-checking failure. Type-system evolution remains a tooling concern. The engine only needs to know which syntax is erasable.
There is still a parser compatibility problem to solve. New syntax must coexist with existing JavaScript, and reserving too much grammar could constrain future language features. The proposal acknowledges that accommodating multiple type systems while leaving room for JavaScript's evolution is a design tradeoff.
Recognizing the end of a type is one concrete difficulty. The March text discusses skipping balanced brackets and parentheses, but says the more general delimiter rules remain unsettled. An engine cannot ignore a type annotation unless it can determine exactly where ordinary executable code resumes.
Erasure excludes constructs that generate behavior
The announcement excludes enums, namespaces and parameter properties because they generate observable runtime behavior. An engine could not implement them merely by ignoring their syntax. Those constructs would need separate language proposals or would continue to require compilation.
JSX is also outside the March proposal. Its syntax transforms into executable code, and it is independent of optional static types. A web application using JSX could therefore still need a transformation step even if the proposed annotation syntax eventually became available.
This limits the claim about removing builds. A program using only supported JavaScript plus erasable annotations might avoid type erasure as a build task. A program using other transformations would still need them. Bundling and production optimization would remain separate decisions with their own costs and benefits.
The proposal does not require existing TypeScript projects to change. TypeScript can retain its complete language and continue compiling code outside the proposed subset. Developers could choose a restricted subset when direct execution is useful. That choice would be optional rather than a retroactive change to all TypeScript source.
I prefer that explicit scope to treating every TypeScript feature as a candidate for immediate standardization. The useful question is which annotations can disappear without altering execution. Features that create values or transform program behavior need a different justification.
Module syntax needs an erasure rule too
Type declarations often refer to declarations in other files. The March text therefore includes type-only imports and exports. A fully type-only import would be ignored and would not trigger module resolution or module inclusion during execution.
That matters because an ordinary import can cause a module to execute. A syntax proposal cannot merely say types disappear while leaving readers uncertain about the import that names them. It must specify which declarations have runtime module behavior and which exist solely for the checker.
The draft also distinguishes a statement declared type-only from an ordinary import whose individual bindings are marked type-only. Its example says the latter can still import the module at runtime. That is a proposed distinction, and its presence shows why erasure needs rules at the statement level as well as around annotations.
A toolchain adopting a common grammar would need to preserve those distinctions consistently. Otherwise removing a type could accidentally remove a module's side effects or introduce a runtime dependency that the source intended only for checking. The draft treats those effects as part of the execution contract.
Generic calls expose an existing syntax collision
TypeScript permits explicit type arguments on a call, but the proposal notes that this spelling can already be valid JavaScript with another interpretation. Reusing it without a distinguishing marker would change the meaning of existing programs.
The March draft offers a double-colon prefix as one possible disambiguation. It explicitly says no particular solution is proposed at that point. That example is evidence of an unresolved grammar question, not an approved new operator that application authors should start using.
This is a useful limit on claims of complete source compatibility. A proposal can aim to accept a large subset of TypeScript while still requiring concessions where TypeScript's parser uses information that standard JavaScript grammar does not. The details determine which existing files could execute directly.
The announcement names Rob Palmer at Bloomberg and Romulo Cintra at Igalia as co-champions, alongside the TypeScript team's collaboration, and credits Gil Tayar's work on the proposal. Their immediate task is to bring the design to the committee for consideration. As of this announcement, the executable contract remains a proposal whose grammar and supported subset still require agreement.