Repository: TypeScript
Issue: Proposal: Easier Migration with Loose Mode in TypeScript Files
Labels: Suggestion,Awaiting More Feedback

This issue is the dual of #23906.

# Background

TypeScript has always aimed at making migration from JavaScript as easy as possible; however, even today there exists a bit of an awkward gap where you must rewrite your JavaScript code to put it in a state where it's "ready" to be converted to TypeScript. As an example, users might start annotating their code with JSDoc to get better analysis in `.js` files, but once they switch their file extensions to `.ts`, TypeScript pretends like it doesn't understand those annotations anymore.

# Proposal

TypeScript can provide a new "loose" mode (which we'll refer to as `looseTs`). This loose mode can be seen as a hybrid between the `allowJs`/Salsa language service support for JavaScript, along with TypeScript itself.

Let's explore what would this experience would look like.

## Special JavaScript Declarations Are Allowed

TypeScript would understand certain constructs that are currently special cased in JS files. For example, the following construct would create what TypeScript effectively sees as a constructor.

```ts
function Foo() {
    this.x = 10;
    this.y = 20;
    this.z = 30;
}

new Foo().x + new Foo().y + new Foo().z // all well-typed as 'number'
```

Our language service could provide tooling to help refactor this to a more canonical sort of class.

## Type Annotations & Declarations

All TypeScript constructs would continue to work, but so would JSDoc annotations & declarations.

```ts
/**
 * @typedef {PersonName} string
 */

export interface Person {
    // valid to reference JSDoc declarations in the same file
    name: PersonName;
}
```

TypeScript constructs would always take precedent over their JSDoc counterparts when they potentially conflict. For example, the following provides an error at worst, but will always consider `x` to be a `string`:

```ts
/**
 * @type {number}
 */
var x: string;
```

## Class Properties

Today, TypeScript requires all classes to have property declarations.

Future versions of ECMAScript might *allow* property declarations.

The story here is: pick one. If classes contain no property declarations, then we'll fall back to Salsa-style inference from the constructor body. If any property declarations are present, then any access to `this` with a member that hasn't been declared is an error.

```ts
// Good!
class AllDeclared {
    a: number;
    constructor() {
        this.a = 0;
    }
}

// Good!
// Also, users get a quick fix.
class OnlyInitialized {
    constructor() {
        this.a = 0;
    }
}

// Bad!
class MixedDeclarationsAndInitialization {
    a: number;
    constructor() {
        this.a = 10;
        this.b = "hallo";
    }
}
```

We can provide tooling to help migrate users to TypeScript code that declares all of the initialized properties.

## Best-Effort Completions

Like in Salsa, we should provide loose completions for things like `any` by default. This might be editor-configurable, but see #5334 for some more discussion.

## More?

Your ideas here!

# Drawbacks

One argument is that this could potentially dilute the value of the language, similar to concerns around `// @ts-ignore`.

Another related argument has to do with cognitive overhead. Our heuristics around understanding JavaScript constructs in Salsa (our JS language service) feels somewhat opaque. While we can document what special constructs we support, TypeScript's current model is significantly simpler. It might not be clear what features "proper TypeScript" actually supports (i.e. what exactly are you giving up when you turn off `looseTs`?)

# Alternatives

We may want to consider alternatives before we commit to something like this.

## Type Annotations in JavaScript Files

This proposal has proposed the idea of understanding Salsa/JS constructs in `.ts` files, but one could approach it from the other direction: Salsa could support type annotations in `.js` files instead under a specific mode. Our main concern here has been the conflation between what is possible in JavaScript today, and what constructs are specific to TypeScript. Additionally, providing non-standard constructs in `.js` files might give users the wrong impression over what we're trying to achieve (to clarify, in this issue, we're here to provide tooling for JavaScript users and make it easier to migrate to TypeScript).

## Tooling Tooling Tooling Tooling

Now that we have suggestion diagnostics, we can potentially provide suggestions & tooling to just fix "legacy" JS constructs in the language service once you've moved to TypeScript. The counter-point here is that users will still likely experience the "sea of red" problem when you first switch a file over to `.ts`.