question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Feature Request] Proposal for type annotations as comments

See original GitHub issue

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 in the issue threads of the TC39 proposal.)

🔍 Search Terms

“jsdoc alternative”, “jsdoc”, “flotate”, “flow comments”

✅ Viability Checklist

My suggestion meets these guidelines:

  • This wouldn’t be a breaking change in existing TypeScript/JavaScript code
  • This wouldn’t change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn’t a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript’s Design Goals.

⭐ Proposal

A JavaScript file would be preceded by

// @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:

// @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:

function stringsStringStrings(p1 /*: string */, p2 /*?: string */, p3 /*?: string */, p4 = "test") /*: string */ {
    // TODO
}

/*::
interface Person {
    name: string;
    age: number;
}
type CoolBool = boolean;
*/
//:: import type { Person } from "schema"

let person //: Person
// 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:

/*::
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).
  2. 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.
  3. 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.

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:13
  • Comments:30 (2 by maintainers)

github_iconTop GitHub Comments

5reactions
lillallolcommented, Apr 13, 2022

That’s not everyone’s experience

Lets be more specific with examples here.

I think it’s clearly articulated by even people on the TypeScript team that the JSDoc flow is not the greatest experience

What do you mean by JSDoc flow? You mean the way I suggest? If yes then I would like to have some links, or at least if ts maintainers see that, have a discussion on that, here.

But it’s a clearly articulated need by other developers.

There is already a solution for that need, which actually promotes best practices (separation of intent and implementation) rather than embracing bad practices (embracing of mixing intent with implementation). From what you suggest we end up hard coding .js files with ts. This is not done with the way I suggest : /**@type {import("some/path/without/ts/extension").IMyType}*/. That path can refer to .ts or a flow file or whatever. Like this you can make your code base work for any type system without having to change the .js or .ts files.

If your response is :

but this bad practices is already supported by ts compile to js method

then I would like to make myself crystal clear on that one: compiling ts to js as inferior way of developing to what I suggest (read here for more).

2reactions
Jack-Workscommented, Apr 12, 2022

Another concise comemnt suggested in that proposal is:

//:: TypeA, TypeB => ReturnType
function f(a, b) {
    return a.handle(b)
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Type annotations (aka, types as comments) - LogRocket Blog
Recently, a new ECMAScript proposal called type annotations (previously referred to as types as comments) was revealed.
Read more >
Typed JavaScript? For real? The type annotations ... - YouTube
A major earthquake has hit TC39, the JavaScript standards committee. A proposal for adding type annotations to JavaScript has just landed on ...
Read more >
Second Life Jira tutorial: Feature Requests - Inara Pey
Use the New Feature Request form as a kind of “executive summary” of the idea, and submit it with the proposal attached as...
Read more >
Type Annotations in JavaScript - Fusebit
Request Fusebit Demo. Static Typing is the number one feature missing in JavaScript, according to 16K developers participating in the State ...
Read more >
Attributes in PHP 8 • PHP.Watch
After years of discussions, feature requests, and user-land implementations such as Doctrine Annotations, Attributes proposal for PHP 8 is finally accepted!
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found