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

ES6 should be valid TypeScript #2606

Closed
ChristianKohler opened this issue Apr 3, 2015 · 13 comments
Closed

ES6 should be valid TypeScript #2606

ChristianKohler opened this issue Apr 3, 2015 · 13 comments
Labels
Duplicate An existing issue was already created Question An issue which isn't directly actionable in code

Comments

@ChristianKohler
Copy link

Since TypeScript is a superset of JavaScript it should be possible to compile ES6 code without errors.

This valid ES6 snippets throws the following error:

Error:(3, 14) TS2339: Property 'weight' does not exist on type 'Car'.
class Car {
    constructor(weight) {
        this.weight = weight;
    }
}

Is this a bug or a 'feature'?

@danielearwicker
Copy link

You'll find with your example that although the compiler says the code has a type error, it will still emit valid ES, e.g. as ES5:

var Car = (function () {
    function Car(weight) {
        this.weight = weight;
    }
    return Car;
})();

TS has three levels of correctness. If the input code is syntactically correct (prior to type checking) then it can generate ES output, and it is "valid" TS. At this first level, TS is a superset of ES, in that the set of valid TS programs is larger than the set of valid ES programs (because it includes all the valid ES programs plus those with type annotations).

The second level is type-correctness, which is what your error is complaining about. At this level, TS can act as a subset of ES: some valid ES programs, such as your example, are not type-correct TS programs.

So if you want your program to jump both these hurdles, then is TS is not a simple superset of ES. If it was, then there would be no value at all in having a static type system, as it would accept every ES program without errors, and so add no value over ordinary ES. So this is most definitely a feature, not a 'bug'.

Note that you can effectively eradicate level 1 by using the --noEmitOnError flag.

An alternative approach that a compiler could adopt would be to infer from your constructor code that the class Car must have a property called weight (although it would have to give it the type any).

But TS takes the approach of requiring you to declare the shape of your classes and modules. This is important because it means that you will know when you are making a change that will affect callers, i.e. when you are changing the interfaces between separated concerns in your code:

class Car {
    weight: number;

    constructor(weight: number) {
        this.weight = weight;
    }
}

Note I've also added an explicit statement of the type of the parameter to the constructor. This satisfies the third level of correctness: noImplicitAny, in which the compiler is not allowed to automatically give the type any to variables for which it cannot deduce a more specific type (with one exception: free functions have a this of type any, but hopefully that will be fixed soon!)

@mhegazy mhegazy added the Question An issue which isn't directly actionable in code label Apr 3, 2015
@danquirk
Copy link
Member

danquirk commented Apr 3, 2015

I'll note that we have had requests for better support for this particular pattern. I can't find the related issues right now (that's happening more frequently these days...)

@nycdotnet
Copy link

#766
#2393

;-)

Note for the original poster, this will work as you expect:

class Car {
    constructor(public weight) {
    }
}

emits as:

var Car = (function () {
    function Car(weight) {
        this.weight = weight;
    }
    return Car;
})();

@basarat
Copy link
Contributor

basarat commented Apr 4, 2015

Perhaps #766 should reopened and #2606 and #2393 closed as duplicates. Or even create a new clean issue, if you don't like existing proposals and mark all these as duplicates ❤️

@DanielRosenwasser DanielRosenwasser added Duplicate An existing issue was already created and removed Duplicate An existing issue was already created labels Apr 4, 2015
@DanielRosenwasser
Copy link
Member

I just jumped between marking this as a duplicate and turning this into a meta-issue, but I don't think we can turn something this broad into a meta issue.

@DanielRosenwasser
Copy link
Member

I think that in general, the cost of the solution to this on the user end (declaring a member) is not high enough to add complexity to the type system, which itself is incurred on the user as well.

@basarat
Copy link
Contributor

basarat commented Apr 4, 2015

Duplicate of #766

@ChristianKohler
Copy link
Author

Thank you all for the comprehensive clarification. That was quick :-)

I agree with @sccolbert (#2393):

I was coming at this question from the angle of a new user gradually moving some existing ES6 project to TypeScript. When TypeScript claims (aims) to be a "superset of ES6", a new user would expect valid ES6 code to compile without error, just like this ES5 code compiles without error..

I think that a big part of the success of less/scss is due to the full compatibility with css. Just start with css syntax and gradually learn/use more and more superset features. The same applies to Babel as well. I can just add Babel to my build pipeline without rewriting my exiting code. And I think the same should apply to TypeScript.

I really like how TypeScript becomes more compatible with ES6 with 1.5. But with issues like this, the ES6 circle (from the ngConf slide) will never be completely inside the TypeScript circle and therefore TypeScript wouldn't be a superset of JavaScript but a own language. (Sorry, sounds a little bit harsh)

@DanielRosenwasser: I think, it is not just about the cost of declaring a member in this case but the ES6 compatibility as a whole.

@basarat: I don't understand how #766 is related with ES6 compatibility. Isn't this issue rather a duplicate of #2393?

I am interested on what we should do with issues like these. What about tagging issues which are related to ES6 incompatibly? Or creating a ES6 incompatibility list?

@danielearwicker
Copy link

I think, it is not just about the cost of declaring a member in this case but the ES6 compatibility as a whole.

That's what I assumed you were asking - my comment above is an attempt to answer that wider question.

Slides like the ngConf one you mentioned (concentric circles) are not accurate depictions of compatibility. They are depictions of feature sets. TS is only a compatibility-superset of ES if you ignore static type checking.

@basarat
Copy link
Contributor

basarat commented Apr 17, 2015

This can be eased with tooling though: https://github.com/TypeStrong/atom-typescript#quick-fix

addclassmember

@mhegazy
Copy link
Contributor

mhegazy commented Apr 17, 2015

@basarat this is awesome 🏆 💯

@basarat
Copy link
Contributor

basarat commented Apr 18, 2015

@mhegazy your language service is awesome! 🌹

@DanielRosenwasser
Copy link
Member

💯

Very cool @basarat

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

7 participants