Repository: TypeScript
Issue: [Feature Request] Proposal for type annotations as comments
Labels: Suggestion,In Discussion

# Problem

1. There are many authors that want to use TypeScript without a build step
2. JSDoc is a verbose substitute for TypeScript and doesn't support all TS features.
3. The above 2 problem statements are articulated in https://github.com/tc39/proposal-type-annotations, but it's unclear if that proposal will be accepted, and it would be a more limited subset of TypeScript. This could be implemented today, with a much lower lift.

# Suggestion

This is not a new idea. It is a fleshed-out proposal for https://github.com/microsoft/TypeScript/issues/9694 and is also based on the prior art of https://flow.org/en/docs/types/comments/. #9694 was marked as "Needs Proposal" so this is an attempt at that proposal. (There is also[ prior art / similar conclusions & asks](https://github.com/tc39/proposal-type-annotations/issues/127#issuecomment-1083374687) in the issue threads of the TC39 proposal.)

## 🔍 Search Terms

"jsdoc alternative", "jsdoc", "flotate", "flow comments"

## ✅ Viability Checklist

My suggestion meets these guidelines:

* [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [x] This wouldn't change the runtime behavior of existing JavaScript code
* [x] This could be implemented without emitting different JS based on the types of the expressions
* [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).


## ⭐ Proposal

A JavaScript file would be preceded by 
```js
// @ts
```
The reason this is needed is to indicate the author's intent at
1. Type-checking this JavaScript file as adhering to _all_ of TypeScript's restraints (the TSConfig file), so a stronger version of `@ts-check`.
2. Interpreting special comments as TypeScript types / blocks

Types of comment blocks:

- `/*: Foo*/` is the equivalent of `: Foo` (a type) in TypeScript. Other type modifiers like `/*?: Foo */` are also interpreted plainly as `?: Foo`
- `/*:: statement*/` is the equivalent of `statement` in TypeScript, and used to mark complete `type` / `interface` blocks and other types of assertions.
- Intuitively, an author may use `//:` and `//::` when the type / type import occupies the whole line / remainder of the line

Here's a basic example, borrowed from Flow:
```js
// @ts

/*::
type MyAlias = {
  foo: number,
  bar: boolean,
  baz: string,
};
*/

function method(value /*: MyAlias */) /*: boolean */ {
  return value.bar;
}

method({ foo: 1, bar: true, baz: ["oops"] });
```
The TypeScript compiler would interpret `/*: */` and `/*:: */` as type annotations for TypeScript, making the entire JavaScript file a complete and valid TypeScript file, something that JSDoc does not provide.

Here are some other examples, borrowed from the TC39 proposal:
```js
function stringsStringStrings(p1 /*: string */, p2 /*?: string */, p3 /*?: string */, p4 = "test") /*: string */ {
    // TODO
}

/*::
interface Person {
    name: string;
    age: number;
}
type CoolBool = boolean;
*/
```

```js
//:: import type { Person } from "schema"

let person //: Person
```
```js
// Type assertion
const point = JSON.parse(serializedPoint) //:: as ({ x: number, y: number })

// Non-nullable assertion - a little verbose, but works where JSDoc doesn't!
document.getElementById("entry")/*:: ! */.innerText = "..."

// Generics
class Box /*:: <T> */ {
    value /*: T */;
    constructor(value /*: T */) {
        this.value = value;
    }
}

// Generic invocations
add/*:: <number> */(4, 5)
new Point/*:: <bigint> */(4n, 5n)

// this parameter 
function sum(/*:: this: SomeType, */ x /*: number */, y /*: number */) {
    return x + y
}

// The above can be written in a more organized fashion like
/*::
type SumFunction = (this: SomeType, x: number, y: number) => number
*/
const sum /*: SumFunction */ = function (x, y) {
    return x + y
}

// Function overloads - the TC39 proposal (and JSDoc?) cannot support this
/*::
function foo(x: number): number
function foo(x: string): string;
*/
function foo(x /*: string | number */) /*: string | number */ {
    if (typeof x === number) {
          return x + 1
    }
    else {
        return x + "!"
    }
}

// Class and field modifiers
class Point {
    //:: public readonly
    x //: number
}
```

**Important Note:** an author should not be able to put _any_ content in `/*:: */` blocks. For example, this should be flagged as invalid:
```js
/*::
function method(value: MyAlias): boolean {
  return value.bar;
}
*/

method({ foo: 1, bar: true, baz: ["oops"] });
```
Yes, the content of the `/*:: */` is "valid TypeScript", but the engine should distinguish between type annotations / assertions from code that is to be available at runtime.

## 📃 Motivating Example

A lot of the motivations for this are the exact same as https://github.com/tc39/proposal-type-annotations; but this approach just solves it a different way, and could be done much sooner. The TypeScript engine would need to do little more than replace comment blocks in conforming `.js` files and then just immediately treat it as if it were a plain ol' TypeScript file.

## 💻 Use Cases

**What do you want to use this for?**
This would allow teams / individuals / myself to use TypeScript without a build step! Gone would be "compile times" while developing.

**What shortcomings exist with other approaches?**

1. The TC39 proposal is more limited than this proposal, for syntax space reasons
2. JSDoc-based type-checking is more limited than this proposal, in that it doesn't support certain types, imports / exports, and as extensive of type-checking. This would support full type-checking of JavaScript.

**What shortcomings exist with this approach?**

1. This is, of course, more verbose than plain TypeScript but it is, it should be noted, much less verbose than using JSDoc for typing (and would support all of TypeScript, unlike JSDoc).
3. There would be, of course, some tooling support that wouldn't be present at first. For example, linters would need / want to be "TypeScript-aware", to lint the code within comment blocks. And code coloring / Intellisense should work in IDEs like VSCode to treat comment blocks like plain TypeScript. But I would anticipate support coming quickly from the community.
4. The author would need to be aware that this is really just for type annotations. That is, one could not put any runtime TypeScript in `/*:: */` because that would defeat the purpose. So there may be some initial confusion around usage. See the above example.

**What workarounds are you using in the meantime?**
There are no current workarounds, to meet these particular goals. If you a) want to use all of TypeScript, b) don't want a build step in your JS files, there is no solution. Also, to again re-iterate the point, the TC39 proposal would also not meet these goals (like JSDoc, it also cannot support all of TypeScript), so there are benefits of doing this regardless of the outcome of that proposal.