Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Easier Migration with Loose Mode in TypeScript Files #22665

Open
DanielRosenwasser opened this issue Mar 16, 2018 · 2 comments
Open
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Mar 16, 2018

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.

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.

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

/**
 * @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.

// 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.

@DanielRosenwasser DanielRosenwasser added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Mar 16, 2018
@RyanCavanaugh
Copy link
Member

Open questions that would need to be determined:

  • Which behavior would we choose for unspecified generic type arguments?
  • Do we bring over behavior like "magic" require or module.exports ?
  • I still think all classes in TS should get auto-inferred properties from this constructor assignments when there are no property declarations 😠
  • What happens to {}-initialized variables? In JS they get special treatment IIRC

Let's say someone writes this

/**
 * @type {number}
 */
var x;

Is there any world where we don't want x to have type number? It seems somewhat orthogonal to "loose"ness.

@DanielRosenwasser
Copy link
Member Author

DanielRosenwasser commented Mar 17, 2018

I think to all of your questions above, the answer is "whatever Salsa does today, do it here". The only thing I'm vaguely conflicted about is the constructor properties thing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

2 participants