{"id":13483142,"url":"https://github.com/tc39/proposal-type-annotations","last_synced_at":"2025-05-13T20:19:41.166Z","repository":{"id":37462659,"uuid":"322608016","full_name":"tc39/proposal-type-annotations","owner":"tc39","description":"ECMAScript proposal for type syntax that is erased - Stage 1","archived":false,"fork":false,"pushed_at":"2025-02-15T15:57:32.000Z","size":1477,"stargazers_count":4332,"open_issues_count":98,"forks_count":48,"subscribers_count":221,"default_branch":"main","last_synced_at":"2025-04-28T11:54:54.040Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://tc39.es/proposal-type-annotations/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tc39.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-12-18T13:49:01.000Z","updated_at":"2025-04-26T20:36:19.000Z","dependencies_parsed_at":"2024-05-30T05:10:03.851Z","dependency_job_id":"7c43d6a0-970d-4afe-8668-a81f5ca3dfbc","html_url":"https://github.com/tc39/proposal-type-annotations","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-type-annotations","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-type-annotations/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-type-annotations/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-type-annotations/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tc39","download_url":"https://codeload.github.com/tc39/proposal-type-annotations/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254020659,"owners_count":22000757,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T17:01:08.575Z","updated_at":"2025-05-13T20:19:41.125Z","avatar_url":"https://github.com/tc39.png","language":"JavaScript","readme":"\u003e ⚠️ *This document has not been updated regularly. See TC39 meeting notes from 2022 ([March 29](https://github.com/tc39/notes/blob/main/meetings/2022-03/mar-29.md#types-as-comments-for-stage-1), [March 31](https://github.com/tc39/notes/blob/main/meetings/2022-03/mar-31.md#types-as-comments-continuation)) and 2023 ([March 22](https://github.com/tc39/notes/blob/main/meetings/2023-03/mar-22.md#type-annotations-proposal-update), [September 27](https://github.com/tc39/notes/blob/main/meetings/2023-09/september-27.md#type-annotations-stage-1-update-and-discussion)) for the most up-to-date information.*\n\n# ECMAScript proposal: Type Annotations\n\nThis proposal aims to enable developers to add type annotations to their JavaScript code, allowing those annotations to be checked by a type checker that is _external to JavaScript_.\nAt runtime, a JavaScript engine ignores them, treating the types as comments.\n\nThe aim of this proposal is to enable developers to run programs written in [TypeScript](https://www.typescriptlang.org/), [Flow](https://flow.org/), and other static typing supersets of JavaScript without any need for transpilation, if they stick within a certain reasonably large subset of the language.\n\n## Status\n\n**Stage:** 1\n\n**Authors:**\n\n- Gil Tayar\n- Daniel Rosenwasser (Microsoft)\n- Romulo Cintra (Igalia)\n- Rob Palmer (Bloomberg)\n- ...and a number of contributors, see [history](https://github.com/tc39/proposal-type-annotations/commits/master).\n\n**Champions:**\n\n- Daniel Rosenwasser (Microsoft)\n- Romulo Cintra (Igalia)\n- Rob Palmer (Bloomberg)\n\nPlease leave any feedback you have in the [issues](https://github.com/tc39/proposal-type-annotations/issues)!\n\n## Motivation: Unfork JavaScript\n\nOver the past decade, the case for static type-checking has been proven out fairly successfully.\nMicrosoft, Google, and Facebook released [TypeScript](https://www.typescriptlang.org/), [Closure Compiler](https://developers.google.com/closure/compiler/), and [Flow](https://flow.org/), respectively.\nThese efforts have been large investments in JavaScript to reap the productivity gains they saw in other statically-typed languages including finding errors earlier on, and leveraging powerful editor tooling.\n\nIn the case of TypeScript, Flow, and others, these variants of JavaScript brought convenient syntax for declaring and using types in JavaScript.\nThis syntax mostly does not affect runtime semantics, and in practice, most of the work of converting these variants to plain JavaScript amounts to erasing types.\n\nThe strong demand for ergonomic type annotation syntax has led to forks of JavaScript with custom syntax. This has introduced developer friction and means widely-used JavaScript forks have trouble coordinating with TC39 and must risk syntax conflicts. This proposal formalizes an ergonomic syntax space for comments, to integrate the needs of type-checked forks of JavaScript.\n\n### Community Usage and Demand\n\n_Static Typing_ was the most requested language feature in the [_State of JS_ survey](https://stateofjs.com) in [2020](https://2020.stateofjs.com/en-US/opinions/missing_from_js/), [2021](https://2021.stateofjs.com/en-US/opinions/#currently_missing_from_js_wins), [2022](https://2022.stateofjs.com/en-US/opinions/#top_currently_missing_from_js) and [2023](https://2023.stateofjs.com/en-US/features/#language_pain_points).\n\n![missing-features-js](https://user-images.githubusercontent.com/6939381/143012138-96b93204-c456-4ab5-bb63-2648187ab8a7.png)\n\n\n### Trends in JavaScript Compilation\n\nThe rise of type syntax in JavaScript coincided with the rise of *downlevel compilation* (sometimes called \"transpilation\").\nAs ES2015 was standardized, JavaScript developers saw wonderful new features they could not immediately use because of constraints around supporting older browsers.\nFor example, an arrow function could provide developer ergonomics, but wouldn't run on every end-user's machine.\nAs a result, projects like Traceur, TypeScript, and Babel filled the gap by rewriting ES2015 code into equivalent code that would work on older runtimes.\n\nBecause type syntax is not natively supported in JavaScript, some tool had to exist to remove those types before running any code.\nFor type systems like TypeScript and Flow, it made sense to integrate a type erasure step with a syntax-downleveling step, so that users wouldn't need to run separate tools.\nMore recently, some bundlers have even started doing both.\n\nBut over time, we anticipate there will be less need for developers to downlevel-compile.\nEvergreen browsers have become more of the norm, and on the back-end, Node.js and Deno use very recent versions of V8.\nOver time, for many static type system users, the only necessary step between writing code and running it will be to erase away type annotations.\n\nBuild steps add another layer of concerns to writing code.\nFor example, ensuring freshness of the build output, optimizing the speed of the build, and managing sourcemaps for debugging, are all concerns that JavaScript initially side-stepped.\nThis simplicity made JavaScript much more approachable.\n\nThis proposal will reduce the need to have a build step which can make some development set-ups much simpler.\nUsers can simply run the code they wrote.\n\n### Limits of JSDoc Type Annotations\n\nWhile build tools are not terribly difficult to use, they are yet another barrier to entry for many developers.\nThis is in part why the TypeScript team invested in support for expressing types in JSDoc comments.\nJSDoc comments had some existing precedence in the JavaScript community for documenting types, and these types were leveraged by the Closure compiler.\n\nThis comment convention is often found in build scripts, small web apps, server-side apps, and elsewhere where\nthe cost/benefit tradeoff of adding a build-tool is too high.\nEven when no type-checking diagnostics put in place, the comment convention is still leveraged in editors supporting types in their underlying JavaScript editing experience.\n\nHere's an example of the JSDoc-based type syntax from [TypeScript's JSDoc Reference](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#param-and-returns).\n\n```js\n/**\n * @param {string}  p1 - A string param.\n * @param {string=} p2 - An optional param (Closure syntax)\n * @param {string} [p3] - Another optional param (JSDoc syntax).\n * @param {string} [p4=\"test\"] - An optional param with a default value\n * @return {string} This is the result\n */\nfunction stringsStringStrings(p1, p2, p3, p4=\"test\") {\n    // TODO\n}\n```\n\nAnd here's the proposed syntax, that's compatible with the majority of type-checkers.\n\n```ts\nfunction stringsStringStrings(p1: string, p2?: string, p3?: string, p4 = \"test\"): string {\n    // TODO\n}\n```\n\nJSDoc comments are typically more verbose.\nOn top of this, JSDoc comments only provide a subset of the feature set supported in TypeScript,\nin part because it's difficult to provide expressive syntax within JSDoc comments.\n\nNevertheless, the JSDoc-based syntax remains useful, and the need for some form of type annotations in JavaScript was significant enough for the TypeScript team to invest in it and the community to create tooling to support type-checking using JSDoc\u003csup\u003e[[1](https://www.npmjs.com/package/flow-jsdoc)], [[2](https://www.npmjs.com/package/babel-plugin-jsdoc-runtime-typecheck)]\u003c/sup\u003e.\n\nFor these reasons, this proposal explores and expects to a larger syntax to appear as-is in JavaScript source files, interpreted as comments.\n\n## Proposal\n\n\u003e The following is a Stage 1 proposal. Please treat it as such, updates are expected and [feedback](https://github.com/tc39/proposal-type-annotations/issues/new) is welcome. [TC39 stage process document](https://tc39.es/process-document/)\n### Type Annotations\n\nType annotations allow a developer to explicitly state what type a variable or expression is intended to be.\nAnnotations follow the name or binding pattern of a declaration.\nThey start with a `:` and are followed by the actual type.\n\n```ts\nlet x: string;\n\nx = \"hello\";\n\nx = 100;\n```\n\nIn the example above, `x` is annotated with the type `string`.\nTools doing static type analysis can utilize that type, and might choose to error on the statement `x = 100`;\nhowever, a JavaScript engine that follows this proposal would execute every line here without error.\nThis is because annotations do not change the semantics of a program, and are equivalent to comments.\n\nAnnotations can also be placed on parameters to specify the types that they accept, and following the end of a parameter list to specify the return type of a function.\n\n```ts\nfunction equals(x: number, y: number): boolean {\n    return x === y;\n}\n```\n\nHere we have specified `number` for each parameter type, and `boolean` for the return type of `equals`.\n\n### Type Declarations\n\nMuch of the time, developers need to create new names for types so that they can be easily referenced without repetition and so that they can be declared recursively.\n\nOne way to declare a type - specifically an object type - is with an interface.\n\n```ts\ninterface Person {\n    name: string;\n    age: number;\n}\n```\n\nAnything declared between the `{` and `}` of an `interface` is entirely ignored.\n\nA type alias is another kind of declaration.\nIt can declare a name for a broader set of types.\n\n```ts\ntype CoolBool = boolean;\n```\n\n### Classes as Type Declarations\n\nThis proposal would allow class members, like property declarations and private field declarations, to specify type annotations.\n\n```ts\nclass Person {\n    name: string;\n    constructor(name: string) {\n        this.name = name;\n    }\n\n    getGreeting(): string {\n        return `Hello, my name is ${this.name}`;\n    }\n}\n```\n\nFor most type-checkers, annotated class members would contribute to the type produced by constructing a given class.\nIn the above example, a type-checker could assume a new type named `Person`, with a property `name` of type `string` and a method `getGreeting` that returns a `string`;\nbut like any other syntax in this proposal, these annotations do not weigh into the runtime behavior of the program.\n\n### Kinds of Types\n\nThe above examples use type names like `string`, `number`, and `boolean`, the majority of static type-checkers support types with more involved syntax than just a single identifier.\nSome examples are given in the following table.\n\nName                                 | Example\n-------------------------------------|--------\nTypes References with Type Arguments | `Set\u003cstring\u003e`\nObject Types                         | `{ name: string, age: number }`\nArray Type Shorthand                 | `number[]`\nCallable Type Shorthand              | `(x: string) =\u003e string`\nConstructable Type Shorthand         | `new (b: Bread) =\u003e Duck`\nTuple Types                          | `[number, number]`\nUnion Types                          | `string \\| number`\nIntersection Types                   | `Named \u0026 Dog`\n`this` Types                         | `this`\nIndexed Access Types                 | `T[K]`\n\nThis table is not comprehensive.\n\nThe goal of this proposal is to find a reasonable set of syntactic rules to accommodate these constructs (and more) without prohibiting existing type systems from innovating in this space.\n\nThe challenge with this is denoting the *end* of a type - this involves stating explicitly what tokens may and may not be part of a comment.\nAn easy first step is to ensure that anything within matching parentheses and brackets (`(...)`, `[...]`, `{...}`, or `\u003c...\u003e`) can be immediately skipped.\nGoing further is where things get harder.\n\nThese rules have not yet been established, but will be explored in more detail upon advancement of this proposal.\n\nSee also\n\n* [Allowed types](/syntax/grammar-ideas.md#allowed-types)\n* [Types under consideration](/syntax/grammar-ideas.md#types-under-consideration)\n* [Annotation type delimiters](/syntax/grammar-ideas.md#annotation-type-delimiters-and-allowed-types)\n\n### Parameter Optionality\n\nIn JavaScript, parameters are technically \"optional\" - when arguments are omitted, the parameters of a function will be assigned the value `undefined` upon invocation.\nThis can be a source of errors, and it is a useful signal whether or not a parameter is actually optional.\n\nTo specify that a parameter is optional, the name of that parameter can be followed with a `?`.\n\n```ts\nfunction split(str: string, separator?: string) {\n    // ...\n}\n```\n\n### Importing and Exporting Types\n\nAs projects get bigger, code is split into modules, and sometimes a developer will need to refer to a type declared in another file.\n\nTypes declarations can be exported by prefixing them with the `export` keyword.\n\n```ts\nexport type SpecialBool = boolean;\n\nexport interface Person {\n    name: string;\n    age: number;\n}\n```\n\nTypes can also be exported using an `export type` statement.\n\n```ts\nexport type { SomeLocalType };\n\nexport type { SomeType as AnotherType } from \"some-module\";\n```\n\nCorrespondingly, another module can use an `import type` statement to reference these types.\n\n```ts\nimport type { Person } from \"schema\";\n\nlet person: Person;\n\n// or...\n\nimport type * as schema from \"schema\";\n\nlet person: schema.Person;\n```\n\nThese `type`-specified declarations act as comments as well.\nThey would not trigger any resolution or inclusion of modules.\nSimilarly, their named bindings are not validated, and thus there is no runtime error if a named binding references an entity that was never declared.\nInstead, design-time tools would be free to statically analyze these declarations and issue an error under such conditions.\n\n#### Type-Only Named Bindings\n\nMaintaining separate import statements for values and types can be cumbersome - especially when many modules export both types and values.\n\n```ts\nimport { parseSourceFile } from \"./parser\";\nimport type { SourceFile } from \"./parser\";\n\n// ...\n\nlet file: SourceFile;\ntry {\n    file = parseSourceFile(filePath);\n}\ncatch {\n    // ...\n}\n```\n\nTo support `import` or `export` statements containing both type and value bindings, a user can express which bindings are type-only by prefixing them with the `type` keyword.\n\n```ts\nimport { parseSourceFile, type SourceFile } from \"./parser\";\n```\n\nA major difference with the above is that such imports are retained even if all bindings are declared type-only.\n\n```ts\n// This still imports \"./parser\" at runtime.\nimport { type SourceFile } from \"./parser\";\n```\n \n### Type Assertions\n\nType systems do not have perfect information about the runtime type of an expression.\nIn some cases, they will need to be informed of a more-appropriate type at a given position.\nType assertions - sometimes called casts - are a means of asserting an expression's static type.\n\n```ts\n// TypeScript\nlet value = 1 as number;\n```\n\n```js\n// Flow\nlet value = 1;\n(value: number);\n```\n\nThe term \"type assertion\" was chosen in TypeScript to distance from the idea of a \"cast\" which often has runtime implications.\nIn contrast, type assertions have no runtime behavior.\n\n#### Non-Nullable Assertions\n\nIt's a common use case for type-assertions, the type-checker filters null out of nullable types, checking if value is neither `null` nor `undefined`.\n\nFor example, one can write `x!.foo` to specify that `x` cannot be `null` nor `undefined`.\n\n```ts\n// assert that we have a valid 'HTMLElement', not 'HTMLElement | null'\ndocument.getElementById(\"entry\")!.innerText = \"...\";\n```\n\n\u003eIn TypeScript, the non-null assertion operator has no runtime semantics, and this proposal would specify it similarly;\n\u003e however, there is a case for adding non-nullable assertions as a runtime operator instead.\n\u003e If a runtime operator is preferred, that would likely become an independent proposal.\n\n### Generics\n\nIn modern type systems, it's not enough to just talk about having an `Array` - often, we're interested in what's *in* the `Array` (e.g. whether we have an `Array` of `strings`).\n*Generics* give us a way to talk about things like containers over types, and the way we talk about an `Array` of `strings` is by writing `Array\u003cstring\u003e`.\n\nLike everything else in this proposal, generics have no runtime behavior and would be ignored by a JavaScript runtime.\n\n#### Generic Declarations\n\nGeneric type parameters can appear on `type` and `interface` declarations.\nThey must start with a `\u003c` after the identifier and end with a `\u003e`:\n\n```ts\ntype Foo\u003cT\u003e = T[]\n\ninterface Bar\u003cT\u003e {\n    x: T;\n}\n```\n\nFunctions and classes can also have type parameters, though variables and parameters cannot.\n\n```ts\nfunction foo\u003cT\u003e(x: T) {\n    return x;\n}\n\nclass Box\u003cT\u003e {\n    value: T;\n    constructor(value: T) {\n        this.value = value;\n    }\n}\n```\n\n### Generic Invocations\n\nOne can explicitly specify the type arguments of a generic function invocation or generic class instantiation, [in TypeScript](https://www.typescriptlang.org/docs/handbook/2/functions.html#specifying-type-arguments) or in [Flow](https://flow.org/en/docs/types/generics/).\n\n```ts\nadd\u003cnumber\u003e(4, 5)\nnew Point\u003cbigint\u003e(4n, 5n)\n```\n\nThe above syntax is already valid JavaScript that users may rely on, so we cannot use this syntax as-is.\nWe expect some form of new syntax that could be used to resolve this ambiguity.\nNo specific solution is proposed at this point of time, but one example option is to use a syntactic prefix such as `::`\n\n```ts\n// Types Annotations - example syntax solution\nadd::\u003cnumber\u003e(4, 5)\nnew Point::\u003cbigint\u003e(4n, 5n)\n```\n\nThese type arguments (`::\u003ctype\u003e`) would be ignored by the JavaScript runtime.\nIt would be reasonable for this non-ambiguous syntax to be adopted in TypeScript as well.\n\n### `this` Parameters\n\nA function can have a parameter named `this` as the first parameter, and this parameter (and its type) is ignored by the runtime.\nIt has no effect on the `length` property of the function, and does not impact values like `arguments`.\n\n```ts\nfunction sum(this: SomeType, x: number, y: number) {\n    // ...\n}\n```\n\nIt would be expected that using a `this` parameter in an arrow function would either be disallowed by the grammar, or trigger an early error.\n\n```ts\n// Error!\nconst oops = (this: SomeType) =\u003e {\n    // ...\n};\n```\n\n## Intentional Omissions\n\nWe consider the following items explicitly excluded from the scope of this proposal.\n\n### Omitted: TypeScript-specific features that generate code\n\nSome constructs in TypeScript are not supported by this proposal because they have runtime semantics, generating JavaScript code rather than simply being stripped out and ignored.\nThese constructs are not in the scope of this proposal, but could be added by separate TC39 proposals.\n\n- [Enums](https://www.typescriptlang.org/docs/handbook/enums.html)\n- [Namespaces](https://www.typescriptlang.org/docs/handbook/namespaces.html)\n- [Parameter properties](https://www.typescriptlang.org/docs/handbook/2/classes.html#parameter-properties)\n\n### Omitted: JSX\n\n[JSX](https://facebook.github.io/jsx/) is an XML-like syntax extension to JavaScript that is designed to be transformed by a pre-processor into valid JavaScript.\nIt is widely used in [the React ecosystem](https://reactjs.org/docs/introducing-jsx.html), but it has been used for different libraries and frameworks.\nBecause JSX directly interleaves with JavaScript code, compilers and type-checkers for JavaScript typically also support checking and transforming JSX as well.\nSome users may hope that the JSX transform could also be directly supported by ECMAScript, to expand the set of use-cases that can be handled without a build step.\n\nWe do **not** consider JSX to be in scope of this proposal because:\n\n- JSX is an orthogonal feature that is independent of optional static types. This proposal does not affect the viability of introducing JSX into ECMAScript via an independent proposal.\n- JSX syntax expands into meaningful JavaScript code when transformed. This proposal is only concerned with syntax erasure.\n\n## Up For Debate\n\nA couple pieces of syntax would fit cleanly in with the \"types as comments\" model, but may feel like a bit of overreach.\nWe think that this proposal could work with or without these pieces of syntax, and in some cases present various alternative options below.\n\n### Ambient Declarations\n\nOccasionally it is necessary to inform type-checkers that certain values exist, or even that modules exist.\nType systems have what are called *ambient declarations*, where a declaration will omit its implementation.\nWhile type systems typically have their own \"declaration file\" formats just for declarations like these (e.g. `.d.ts` files in TypeScript, `.flow.js` in Flow, etc.), it can be convenient to declare these values in an implementation file (i.e. a `.js` file) as well.\n\nIn type systems today, a `declare` keyword can precede bindings such as variable, function, and class declarations.\n\n```ts\ndeclare let x: string;\n\ndeclare class Foo {\n    bar(x: number): void;\n}\n\ndeclare function foo(): boolean;\n```\n\nAt the moment, this proposal does not reserve space for ambient declarations, but it is an option.\n\n### Function Overloads\n\nIn existing type systems, function/method declarations may omit their body.\nThis is used for [function overloading](https://www.typescriptlang.org/docs/handbook/functions.html#overloads), which communicates that the return type of a function varies with its inputs.\n\n```ts\nfunction foo(x: number): number\nfunction foo(x: string): string;\nfunction foo(x: string | number): string | number {\n    if (typeof x === number) {\n          return x + 1\n    }\n    else {\n        return x + \"!\"\n    }\n}\n```\n\nAt the moment, this proposal does not reserve space for overload declarations, but it is an option.\n\n### Class and Field Modifiers\n\nSeveral keywords in TypeScript and other type systems are used outside of a type context:\n\n- `abstract` classes and methods\n- `private`, `protected` and `public` placement of fields and methods\n- `readonly` fields\n- `override` fields and methods\n\nAs an example, this proposal could support the following syntax:\n\n```ts\nclass Point {\n    public readonly x: number\n}\n```\n\nIf these are permitted as part of this proposal, the semantics would be to ignore them all, treating the above class the same as the following.\n\n```ts\nclass Point {\n    x;\n}\n```\n\nAs with types, these are \"soft guarantees\" that are not enforced at runtime, but are checked by the type checker.\nThere would likely need to be slightly different syntax to prohibit newlines after these new contextual keywords.\n\nIt might feel strange to include this set of keywords and permit them to be used \"incorrectly\".\nAdditionally, there may be more keywords added over time (e.g. `override` most recently).\n\nAs one way to achieve the same functionality, existing type systems could find a compromise between type annotation syntax and existing comment syntax.\nFor example, TypeScript already supports some of these modifiers in JSDoc.\n\n```ts\nclass Point {\n  /**\n   * @public\n   * @readonly\n   */\n  x: number\n}\n```\n\nThere might be another direction in which this proposal expands comment syntax just to support modifiers like these, which lead with a specific sigil.\n\n```ts\nclass Point {\n  %public %readonly x: number\n\n  @@public @@readonly x: number\n}\n```\n\nThe above ideas try to strike a balance between not overreaching in syntax, while also achieving maximal compatibility with existing type systems.\nWe're open to any of the four solutions presented here, or other ideas people may have.\n\n## FAQ\n\n### Does JavaScript need static type-checking?\n\nGiven how much effort organizations and teams have put into building type-checkers and adopting them, the answer is **yes**.\nPerhaps not every developer will reach for static type-checking, **and that's okay** - that's why this proposal makes type annotations entirely optional;\nhowever, the ecosystem demand for using types is undeniable.\n\nTypeScript has done a great job of demonstrating this - it's gained very widespread use with broad signals that people want to keep using it.\nIt's opt-in, but it has a major presence in the ecosystem, and these days TypeScript support is seen as a huge advantage for libraries.\n\nThe question is not whether JS should have types, but rather \"how should JS work with types?\"\nOne valid answer is that the current ecosystem provides sufficient support where types are stripped out separately ahead-of-time, but this proposal may provide advantages over that approach.\n\n### Why not define a type system for JS in TC39 instead?\n\nTC39 has a tradition of programming language design which favors local, sound checks.\nBy contrast, TypeScript's model -- which has been highly successful for JS developers -- is around non-local, best-effort checks.\nTypeScript-style systems are expensive to check at application startup, and would be redundant every time you run your JavaScript applications.\n\nAdditionally, defining a type system to run directly in the browser means that improved type analyses would become breaking changes **for the users of JavaScript applications**, rather than for developers.\nThis would [violate goals around web compatibility (i.e. \"don't break the web\")](https://github.com/tc39/how-we-work/blob/cc47a79340a773876cb03371dc2d46b9d9ce9695/terminology.md#web-compatibilitydont-break-the-web), so type system innovation would become near-impossible.\nAllowing other type systems to analyze code separately provides developers with choice, innovation, and freedom for developers to opt-out of checking at any time.\n\nIn contrast, trying to add a full type system to JavaScript would be an enormous multi-year effort that would likely never reach consensus.\nThis proposal recognizes that fact, and also recognizes that the community has evolved type systems that it is already happy with.\n\n### How does this proposal relate to TypeScript?\n\nThis proposal is a balancing act: trying to be as TypeScript compatible as possible while still allowing other type systems, and also not impeding the evolution of JavaScript's syntax too much.\nWe acknowledge that full compatibility is not within scope, but we will strive to maximize compatibility and minimize differences.\n\nThis proposal will require work from both ECMAScript and TypeScript itself, where ECMAScript expands its current syntax, but TypeScript makes certain concessions so that types can fit into that space.\nAs mentioned elsewhere, some constructs (like `enum`s and `namespace`s) have been set aside with the option to propose them separately in TC39.\nOthers are still up for discussion (like `class` modifiers and ambient declarations).\nAnd for others, there will need to be work to disambiguate current code (like arrow functions).\n\nTypeScript would continue to exist alongside JavaScript's slightly more restricted type syntax.\nIn other words, **all existing TypeScript projects would continue to compile, and no existing TypeScript codebase would need to change**.\nBut taking any existing TypeScript code that lives outside of JavaScript's type syntax would not run - it would still need to be compiled away.\n\n### Should TypeScript be standardized in TC39?\n\nTypeScript has continued to evolve very quickly in both syntax and type analyses, to the benefit of users.\nTying this evolution to TC39 risks holding that benefit back.\nFor example, TypeScript upgrades often require users to fix type issues because the rules change, and this is often considered \"worth it\" because real bugs are found;\nhowever, this version upgrade path wouldn't be viable for the ECMAScript standard.\nA move to standardization would require more conservatism.\nThe goal here is to enable wider deployment of systems like TypeScript in diverse environments, not obstruct TypeScript's evolution.\n\n### Should TypeScript be sanctioned as JS's official type system?\n\nIt's unclear what it would mean for there to be an \"official\" type system for JavaScript.\nFor example, there is no \"official\" linter or \"official\" formatter for JavaScript.\nInstead there are tools that grow in popularity and evolve over time.\n\nAdditionally, type checkers, such as Flow, Closure, and Hegel may wish to use this proposal to enable developers to use their type checkers to check their code.\nMaking this proposal be only about TypeScript can hamper this effort.\nAmicable competition in this space would be beneficial to JavaScript as it can enable experimentation and new ideas.\n\n### Why not unofficially build TS checking and compilation into various systems?\n\nA number of systems, such as [ts-node](https://github.com/TypeStrong/ts-node) and [deno](https://deno.land/manual/getting_started/typescript), have tried this.\nApart from startup performance issues, a common problem is compatibility across versions and modes, in type checking semantics, grammar, and transpilation output. \nThis proposal would not subsume the needs for all of those features, but it would provide one compatible syntax and semantics to unify around for many needs.\n\n### Why not stick to existing JS comment syntax?\n\nAlthough it is possible to define types in existing JavaScript comments, as Closure and TypeScript's JSDoc mode do, this syntax is much more verbose and unergonomic.\n\nConsider the fact that JSDoc type annotations were present in Closure Compiler prior to TypeScript, and that TypeScript's JSDoc support has been present for years now.\nWhile types in JSDoc has grown over the years, most type-checked JavaScript is still written in TypeScript files with TypeScript syntax.\nThis is similarly the case with Flow, where Flow's type-checker can analyze Flow-like syntax in existing JavaScript comments, but most Flow users continue to just use direct annotation/declaration syntax.\n\n### Don't all JS developers transpile anyway? Will it really help to remove the type-desugaring step?\n\nThe JavaScript ecosystem has been slowly moving back to a transpilation-less future. The sunsetting of IE11 and the rise of evergreen browsers that implement the latest JavaScript standard means that developers can once again run standard JavaScript code without transpilation.\nThe advent of native ES modules in the browser and in Node.js also means that, at least in development, the ecosystem is working its way to a future where even bundling is not necessary.\nNode.js developers in particular, have historically avoided transpilation, and are today torn between the ease of development that is brought by no transpilation, and the ease of development that languages like TypeScript bring.\n\nImplementing this proposal means that we can add type systems to this list of \"things that don't need transpilation anymore\" and bring us closer to a world where transpilation is optional and not a necessity.\n\n### Can types be available via runtime reflection like [TypeScript's emitDecoratorMetadata](https://www.typescriptlang.org/tsconfig#emitDecoratorMetadata)?\n\nThe proposal here differs significantly from Python's types, as the types in this proposal are entirely ignored, not evaluated as expressions or accessible at runtime as metadata.\n\nThis proposal explicitly does not take a stance on runtime reflection leaving further work for future proposals. The main reason is that this proposal does not block further work in this space but rather enables it. This is also the route Python took when adding their types to the language.\n\nUsers who rely on decorator metadata could continue to leverage a build step as desired.\n\n### Does this proposal make all TypeScript programs valid JavaScript?\n\nMost constructs in TypeScript are compatible, but not all,\nand most of those that do not pass can be converted via simple codemod changes\nthat can make them both TypeScript-compatible _and_ compatible with this proposal.\n\nSee the [\"up for debate\"](#up-for-debate) and [\"Intentional Omissions\"](#intentional-omissions) sections for more information.\n\n### Does this proposal make all Flow programs valid JavaScript?\n\nFlow is very similar to TypeScript, and so most type constructs would work, with\na similar caveat in which some types might need to be wrapped in parentheses to be compatible with this proposal.\n\nTwo constructs that do not conform to this proposal are [type casting](https://flow.org/en/docs/types/casting/#toc-type-cast-expression-syntax) (e.g. `(x: number)`) and [`opaque` type aliases](https://flow.org/en/docs/types/opaque-types/) (e.g. `opaque type Meters = number`).\nFlow could consider modifying these in the language so that they conform to this proposal, e.g. adopt the `as` operator as an alternative to `(x: number)`, and `type Meters = (new number)`.\nThis proposal could also reserve room for `opaque` type aliases.\n\n### What about `.d.ts` files and \"libdef\" files?\n\n*Declaration files* and *library definition* files are used by TypeScript and Flow respectively as a kind of \"header\" file that describes values, their types, and where they exist.\nThis proposal can safely ignore them as it does not need to interpret the semantics of the type information inside them.\nTypeScript and Flow will continue reading and analyzing these files as they do today.\n\n### Does this proposal mean that TypeScript developers would have to modify their codebases?\n\nNo. TypeScript can continue to be TypeScript, with no compatibility impact or changes to codebases.\nThis proposal would give developers the _option_ to restrict themselves to a particular subset of TypeScript which would run as JavaScript without transpilation.\n\nDevelopers may still want to use TypeScript syntax for other reasons:\n\n- Use of certain syntax features which are not supported in JavaScript (e.g., `enum`s and parameter properties)\n- Compatibility with existing codebases which may run into certain syntax edge cases that are handled differently\n- Non-standard extensions/reinterpretations of JavaScript (e.g. experimental legacy decorators, decorator metadata, or \\[\\[Set]] semantics for fields)\n\nIf developers decide to migrate an existing TypeScript codebase to use the JavaScript syntax specified in this proposal, the goal of this proposal is that the modifications would be minimal.\nWe believe that many developers would be motivated by removing a build step, but others could decide to stick with TypeScript compilation and enjoy the full power of the language.\n\n### How should tools work with JavaScript type syntax?\n\nGiven the fact that some TypeScript features are [out of scope](#intentional-omissions), and that standard JavaScript will not evolve as fast as TypeScript or support its variety of configurations, there will continue to be an advantage for many tools to support TypeScript in its fuller form, beyond what is potentially standardized as JavaScript.\n\nSome tools currently need a \"plugin\" or option to get TypeScript support working.\nThis proposal would mean that these tools could support type syntax by default, forming a standard, versionless, always-on common base for type syntax.\nFull and prescriptive support for TypeScript, Flow, etc. could remain an opt-in mode on top of that.\n\n### What about compatibility with ReasonML, PureScript, and other statically typed languages that compile to JavaScript?\n\nWhile these languages _compile_ to JavaScript, and have static typing, they are not supersets of JavaScript, and thus are not relevant to this proposal.\n\n### Will the ability to deploy typed source code directly result in bloated applications?\n\nReturning to a world where code does not strictly need to be compiled prior to being used in production means that developers may end up deploying more code than is necessary.\nHence larger payloads over-the-wire for remotely served apps, and more text to parse at load time.\n\nHowever this situation already exists.\nToday, many users omit a build step and ship large amounts of comments and other extraneous information, e.g. unminified code.\nIt remains a best practice to perform an ahead-of-time optimization step on code destined for production if the use-case is performance-sensitive.\n\nSpecifically, note that [the TypeScript compiler `tsc` does not have a built-in option to minify](https://github.com/microsoft/TypeScript/issues/8).  Allowing TypeScript users to skip `tsc` during development will not inherently encourage users to skip a minification step, since minifying TypeScript would have required a separate action in any case.\n\nBabel is another popular transpiler for TypeScript, Flow, and Hegel. Babel's `preset-typescript` and `preset-flow` transpilers do not minify. In Babel, minification requires a separate step (usually performed by a bundler). Allowing Babel users to omit `preset-typescript` will not encourage users to skip minification.\n\nIn this proposal, type annotations are treated as comments. Making comments more useful and easier to use is an appropriate evolution for JavaScript, even when we expect developers to remove comments and type annotations via minification.\n\n### Are unchecked types a footgun?\n\nThis proposal introduces type annotations that are explicitly **not** checked at runtime.\nThis is intentional to minimize the runtime cost of the annotations and to provide a consistent mental model in which the types do not affect program behavior.\nA potential risk is that users might not realize the need to run an external tool to find type errors, and consequently are surprised when type-related bugs arise in their type-annotated code.\n\nFor today's users of external type-checkers, this risk already exists.\nUsers mitigate this risk today via a combination of:\n\n- IDEs that perform type checking and proactively surface type errors\n- Integration of type checking into project development workflows, e.g. npm scripts, CI systems, `tsc`\n\nIn some ways it would be more of a surprise to users if the types *were* runtime-checked.\nIt is common in other languages for there to be minimal runtime type-checking.\nFor example, in C++ there is almost no checking at runtime except for some known cases such as when the programmer requests it, e.g. `dynamic_cast`.\n\nAs seen with TypeScript, developers quickly learn that the types play no role at runtime.\nTherefore similar to the first question of \"Does JavaScript need a static type system?\", this question has been answered, in part, by the widespread success of external type-checkers.\n\n### How could runtime-checked types be added in future?\n\nIt seems unlikely that JavaScript would adopt a pervasive runtime-checked type system due to the runtime performance overhead that it would bring.\nWhile it's possible that there may have been room for improvement, past efforts such as [TS* (Swamy et al)](https://goto.ucsd.edu/~pvekris/docs/safets.pdf) have shown that runtime type-checking based on annotations adds a non-negligible slowdown.\nThat is one reason why this proposal endorses purely static types.\n\nIf there is a desire to keep language open to later adding runtime-checked types, in addition to the static types proposed here, we could make an explicit syntax reservation in the grammar to support both.\n\n### Could this proposal enable runtimes to optimize performance based on type hints?\n\nWhilst it is possible to theorize runtime optimizations driven by statically declared types, the proposal authors are not aware of successful experiments in JavaScript that meaningfully beat dynamic type-driven JIT optimization.\n\nThe proposed type syntax has no defined semantics and so is opaque to the runtimes.\nIt is equivalent to asking _\"Could a runtime use `/** comments **/` to optimize performance?\"_\nTo which the answer is:  almost certainly not - at least not in a standard way.\nTherefore this proposal alone does not directly offer new opportunities for performance improvements.\n\nIt is explicitly a **non-goal** of this proposal to improve the performance of JavaScript.\n\n## Prior Art\n\n### Other languages that have optional erasable type syntax\n\nWhen Python decided to add a gradual type system to the language, it did it in two steps.\nFirst, a proposal for type annotations was created in [PEP-3107 - Function Annotations](https://www.python.org/dev/peps/pep-3107/) that specified parameter types and function return types in Python\nSeveral years later, the places in which types could occur was expanded in [Python PEP-484 - Type Hints](https://www.python.org/dev/peps/pep-0484/).\n\n\nThe proposal here differs significantly from Python's types, as the types in this proposal are entirely ignored, not evaluated as expressions or accessible at runtime as metadata. This difference is largely motivated by the existing community precedent, where JS type systems do not tend to use JS expression grammar for their types, so it is not possible to evaluate them as such.\n\n[Ruby 3 has now also implemented RBS](https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/): type definitions that sit _beside_ the code\nand are not part of it.\n\n#### Languages that add type systems onto JavaScript\n\n[TypeScript](https://www.typescriptlang.org/docs/handbook/intro.html), [Flow](https://flow.org/en/docs/), and [Hegel](https://hegel.js.org/docs) are languages that implement type systems above standard JavaScript.\n\nThe proposal repository contains a [syntax comparison](syntax/syntax-comparison.md) document with a table that compares the type syntax used in these existing systems. It is not exhaustive, and we welcome corrections or contributions.\n\n#### Ability to add type systems to JavaScript via comments\n\nBoth TypeScript and Flow enable developers to write JavaScript code and incorporate\ntypes annotations that the JavaScript runtime ignores.\n\nFor Flow, these are [Flow comment types](https://flow.org/en/docs/types/comments/), and\nfor TypeScript these are [JSDoc comments](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html).\n\nSee the author's blog post on their positive experience with TypeScript's JSDoc comments [here](https://gils-blog.tayar.org/posts/jsdoc-typings-all-the-benefits-none-of-the-drawbacks/).\n\nClosure Compiler's type checking works entirely via JSDoc comments ([docs](https://developers.google.com/closure/compiler/docs/js-for-compiler)). The Closure Compiler team has received many requests for an in-line type syntax, but was hesitant to do this without a standard.\n\n#### Relevant proposals and discussions in TC39\n\nThe earliest proposal for types in JavaScript that we're aware of is [Waldemar Horwat's \"Types\" specification from July 2000](https://www-archive.mozilla.org/js/language/js20-2000-07/libraries/types.html).\n\nThe [proposed draft of ECMAScript 4th edition in 2008](http://archives.ecma-international.org/2008/TC39/tc39-2008-040.pdf) called for types and optional type annotations; TC39 agreed to withdraw the ES4 proposal in 2008, shipping ES 3.1 as ES5 in 2010. [Auth0 has a blog post with a brief history of the saga of ECMAScript 4](https://auth0.com/blog/the-real-story-behind-es4/).\n\nTC39 has previously discussed [guards](https://web.archive.org/web/20141214075910/http://wiki.ecmascript.org/doku.php?id=strawman:guards), which form a new, stronger type system.\n\nPreviously, Sam Goto led discussions around an [optional types proposal](https://github.com/samuelgoto/proposal-optional-types) which aimed to unify syntax and semantics across the type-checkers.\nTrying to find agreement across type-checkers, along with defining a sufficient subset in both syntax and semantics meant that there were difficulties with this approach.\nAn evolution of this plan was [pluggable types](https://github.com/samuelgoto/proposal-pluggable-types) which was [inspired by Gilad Bracha's ideas on pluggable type systems](https://bracha.org/pluggableTypesPosition.pdf).\nThis proposal is extremely similar to the pluggable types proposal, but leans a bit more heavily on the idea of viewing types as comments, and comes at a time with broader adoption of type-checking and a more mature type-checking ecosystem.\n\nIn 2015, Google's V8 team experimented with a proposal to implement a new JS mode that they called \"[Strong Mode](https://docs.google.com/document/d/1Qk0qC4s_XNCLemj42FqfsRLp49nDQMZ1y7fwf5YjaI4/view),\" intending to use types to improve site performance. Google [canceled the experiment in failure](https://groups.google.com/g/strengthen-js/c/ojj3TDxbHpQ). \"In the end we had to give up on this one.\"\n\nThe [optional types proposal repository contains links to other prior discussions around types in JavaScript](https://github.com/samuelgoto/proposal-optional-types/blob/master/FAQ.md#tc39-discussions):\n\n\u003e * 2002 [Javascript 2.0: Evolving a Language for Evolving Systems](http://www-archive.mozilla.org/js/language/evolvingJS.pdf)\n\u003e * 2006 [Type parameters](http://web.archive.org/web/20160425220933/http://wiki.ecmascript.org/doku.php?id=proposals:type_parameters), [Type System](http://web.archive.org/web/20141214152853/http://wiki.ecmascript.org/doku.php?id=clarification:type_system) and [Structural Types and typing of initializers](http://web.archive.org/web/20150622061920/http://wiki.ecmascript.org/doku.php?id=proposals:structural_types_and_typing_of_initializers)\n\u003e * 2011 [Dependent Types for Javascript](https://arxiv.org/abs/1112.4106) ([pdf](http://people.cs.uchicago.edu/~rchugh/static/papers/oopsla12-djs.pdf))\n\u003e * 2011 [Guards](http://web.archive.org/web/20161123223114/http://wiki.ecmascript.org:80/doku.php?id=strawman:guards) and [Trademarks](http://web.archive.org/web/20141214075933/http://wiki.ecmascript.org/doku.php?id=strawman:trademarks)\n\u003e * 2014 [TC39 Discussion on Types](https://github.com/rwaldron/tc39-notes/blob/master/meetings/2014-09/sept-25.md#types): adding syntax without semantics.\n\u003e * 2015 [ES8 gradual typing](https://esdiscuss.org/topic/es8-proposal-optional-static-typing) and [part2](https://esdiscuss.org/topic/optional-static-typing-part-2) and [ecmascript-types](https://github.com/sirisian/ecmascript-types).\n\n### Relevant discussions elsewhere\n\n[Gilad Bracha](https://en.wikipedia.org/wiki/Gilad_Bracha) has [advocated for pluggable type systems](https://bracha.org/pluggableTypesPosition.pdf).\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftc39%2Fproposal-type-annotations","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftc39%2Fproposal-type-annotations","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftc39%2Fproposal-type-annotations/lists"}