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 for Abstract Classes and Methods #3578

Closed
aozgaa opened this issue Jun 19, 2015 · 47 comments
Closed

Proposal for Abstract Classes and Methods #3578

aozgaa opened this issue Jun 19, 2015 · 47 comments
Labels
Committed The team has roadmapped this issue Fixed A PR has been merged for this issue Suggestion An idea for TypeScript

Comments

@aozgaa
Copy link
Contributor

aozgaa commented Jun 19, 2015

Proposal for Keyword abstract

This is a proposal for a new keyword, abstract, to allow for incomplete/partially implemented classes.

Introduction

This proposal expands upon #6, #2946, #2947.

Consider the following situation. A user would like to create a base class that shouldn't be instantiated as a template for derived classes. S/he might write something like

class Animal {
    public age : number;
    public yearsLeft() { return 20 - this.age; }
    public makeSound() : string { return "???"; }
}

class Cow extends Animal {
    makeSound() { return "Moo"; }
}

class Cat extends Animal {
    makeSound() { return "Meow"; }
}

Today, the writer is forced to make a choice: either (i) Animal can be declared an interface, but then yearsLeft cannot have an implementation, or (ii) write the program as above, but then Animal can be instantiated and makeSound has a bogus implementation! Neither of these options is particularly attractive.

We propose abstract as a class declaration modifier to allow the programmer control over whether a class can be instantiated, and as a member function modifier to control whether said member function offers an implementation (and whether the enclosing class is abstract).

Details

The modifier abstract can prepend a class declaration or a member function declaration. Constructors cannot be declared abstract.

  • Objects whose type is typeof C where C is an abstract-declared class (hereafter abstract class) cannot be instantiated via calls to new.
  • A member function declared abstract does not have an implementation.
  • Abstract methods cannot be called within a class member function body via super.foo() where foo is an abstract method belonging to the parent class.
  • Abstract methods may be called within a class member function body via this.foo() where foo is an abstract method belonging to that class.
  • If a class has any abstract methods, then the class itself must be declared abstract.
  • Abstract methods are inherited.
  • Abstract methods can be overridden in the derived class, either by an abstract method (effectively a re-declaration) or a function declaration that offers an implementation.
  • A method cannot be simultaneously abstract and static.
  • A method cannot be simultaneously abstract and private.
  • If an abstract member declaration contains an explicit accessibility modifier, then the modifier must precede the abstract keyword.
  • Overloads on a member function must be either all abstract or all not abstract.
  • Overloads of abstract member functions must be declared adjacent to eachother.
  • Objects whose type is the type of an abstract class can only be assigned to other objects whose type is the type of an abstract class. For example,

The following code snippet summarizes valid and invalid usages of the abstract keyword

class A {
    // ...
}

abstract class B {
    foo(): number { return bar(); }
    abstract bar() : number;
}

new B; // error

import myB = B;
new myB; // error

var BB: typeof B = B;
var AA: typeof A = BB; // error, AA is not of abstract type.
new AA;

function constructB(Factory : typeof B) {
    new Factory; // error -- Factory is of type typeof C
}

var BB = B;
new BB; // error -- BB is of type typeof C

var x : any = C;
new x; // okay -- undefined behavior at runtime


class C extends B { } // error -- not declared abstract

abstract class D extends B { } // okay

class E extends B { // okay -- implements abstract method
    bar() { return 1; }

abstract class F extends B {
    abstract foo() : number;
    bar() { return 2; }
}

abstract class F {
    abstract qux(x : number) : string;
    abstract qux() : number;
    y : number;
    abstract quz(x : number, y : string) : boolean; // error -- declarations must be adjacent

    abstract nom() boolean;
    nom(x : number) boolean: // error -- use of modifier abstract must match on all overloads.
}

class G { // error -- not declared abstract
    abstract baz() : number;
}

Pros

  • Allows the programmer to write partial implementations of a class.
  • Provides a mechanism for the type system to warn about classes that shouldn't be instantiated.
  • abstract annotations clarify the role of base classes in various patterns.

Cons

  • Increases the complexity of the language.

To Be Discussed

  • Should abstract be allowed within class expressions?

Proposed Changes to Grammar

A.6 Classes

  ClassDeclaration:
   abstractopt class Identifier TypeParametersopt ClassHeritage { ClassBody }

  MemberFunctionDeclaration:
   MemberFunctionOverloadsopt MemberFunctionImplementation
   AbstractMemberFunctionOverloads

  AbstractMemberFunctionOverloads:
   AbstractMemberFunctionOverload
   AbstractMemberFunctionOverloads AbstractMemberFunctionOverload

  AbstractMemberFunctionOverload:
   AccessibilityModifieropt abstract PropertyName CallSignature ;

A.10 Ambients

  AmbientClassDeclaration:
   abstractopt class Identifier TypeParametersopt ClassHeritage { AmbientClassBody }

  AbstractOrStatic:
   abstract
   static

  AmbientPropertyMemberDeclaration:
   AccessibilityModifieropt AbstractOrStaticopt PropertyName CallSignature ;

EDIT: updated to clarify the assignability of objects of "abstract type".

@aozgaa aozgaa self-assigned this Jun 19, 2015
@aozgaa aozgaa added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Jun 19, 2015
This was referenced Jun 19, 2015
@CKGrafico
Copy link

Thanks for that!

@mhegazy
Copy link
Contributor

mhegazy commented Jun 20, 2015

Moreover, the assignability of abstract types is restricted to instances that are abstract

I do not understand what you mean by this.

@jbondc
Copy link
Contributor

jbondc commented Jun 22, 2015

  • Increases the complexity of the language.

Pretty much how I feel about it. I'd rather see a more lean functional-like TypeScript then adding astronaut like OO patterns like abstract or decorators.

This overlaps tons with mixins or traits too (combining things from other things). The benefit of traits or mixins is you can design 'abstract patterns' that work with modules too. This proposal is limited to a 'class' which lets face it is really a function under the hood.

@aozgaa
Copy link
Contributor Author

aozgaa commented Jun 22, 2015

@mhegazy This definitely needs re-wording.

We want to prevent the constructor of an abstract class from being invoked. So we wanted to restrict the assignability of the constructor function. Consider the following example:

class A {}
abstract class B extends A {}

var BB: typeof B = B;
var AA: typeof A = BB;
new AA;

We don't want the second assignment to be legal. So we restrict the assignabilty of objects whose type is the type of an abstract class to other objects whose type is the type of an abstract class.

I haven't yet implemented this as part of the attached PR.

I've updated the spec to clarify this.

@zpdDG4gta8XKpMCd
Copy link

@jbondc so true, inheritance (for the sake of code "reuse" or whatever else) is a hands down rotten idea, composition does it all with a little bit more effort, screw this s*t

@Gaelan
Copy link

Gaelan commented Jun 25, 2015

👍

@jbondc
Copy link
Contributor

jbondc commented Jun 25, 2015

💩 I'd love to hear how this aligns with the design goals:

5. Produce a language that is composable and easy to reason about.
6. Align with current and future ECMAScript proposals.

Non-goals
1. Exactly mimic the design of existing languages. Instead, use the behavior of JavaScript 
and the intentions of program authors as a guide for what makes the most sense in the language.

@kitsonk
Copy link
Contributor

kitsonk commented Jun 25, 2015

I have long argued of the merits of embracing the protypical nature of ECMAScript instead of projecting a traditional OO paradigm. On the other hand, that hasn't stopped the wider community rejecting that and ECMAScript has taken a large bend towards traditional OO with ES6, though there seems much debate on this, as several of our ECMAScript luminaries seems to be conflicted on every aspect of this.

@jbondc I think it is a fair challenge to question this proposal in line with design goals 5 and 6. It is very likely that some sort of abstract/traits/composition type features will end up in ES, though there seems to be no common consensus. Both abstract and traits were proposed during the class discussions in ES6/2015, but all got dropped because no one could agree. TypeScript already has interfaces which provide a sufficient level of abstraction ahead of any implementation of something along this line of ES.

The traits discussion (#311) was closed by @RyanCavanaugh because of this conflicting with goal 6. I quote:

There's a lot of overlap here with mix-ins; it would be bad (or at least treacherous) to do both. With mix-ins being a potential part of ES7/ES8+, we want to take the runtime side of this very conservatively and get TC39 to agree on a proposal in this area first.

I honestly don't see what the difference is here.

@jbondc so true, inheritance (for the sake of code "reuse" or whatever else) is a hands down rotten idea, composition does it all with a little bit more effort, screw this s*t

While I am personally a fan of compostability, a strong emotive response without well thought arguments is unlikely to further your thoughts, especially when it appears you want to throw your arms up in the air and walk away. I don't think that is your intent, but that is the way it comes across.

@zpdDG4gta8XKpMCd
Copy link

Here is the statement: inheritance is a dangerous tool that causes more problems than solves

  • it takes knowledge, practice and discipline to use it right (which junior/mid developers generally lack)
  • it takes experience to grasp the understanding where it may NOT be used
  • yet, given all of above, even experienced developers with well designed systems fall short when requirements change and it comes to redesign and it turns out that existing inheritance hierarchies are too rigid to change

All this contributes to frustration, missed deadlines, and myths that coding is hard. In my experience nothing is hard if designed properly. Well, inheritance encourages bad design by allowing developers to violate:

  • (open closed principle)[https://en.wikipedia.org/wiki/Open/closed_principle]
  • (Liskov substitution principle)[https://en.wikipedia.org/wiki/Liskov_substitution_principle]

Besides that

  • having to choose one single super-class among a few possible others inevitably favoring one predecessor over all equally important others, resulting to skewed hierarchies
  • in a sub-class, having to comply to the interface of the super-class even though it goes against the needs
  • leaving a class unclosed and allowing uncontrolled sub-classing that wasn't intended

Besides that, there is quite a number of successful examples of languages without inheritance at all:

  • (COM)[https://www.microsoft.com/com/default.mspx] where code reuse is achieved with interface inheritance and composition only
  • functional lanaguges where code reuse is achieved by various means (parametrizing with functions, typeclasses, class modules) without having to alter the existing code

@DanielRosenwasser
Copy link
Member

Alright, while we'd love to have a constructive conversation on the merits of different approaches in software design, I believe that classes are a useful abstraction and the abstract modifier would bring utility. For those who prefer using this paradigm, it would surely be helpful.

Unless there are specific "gotchas" introduced in our language from abstract that are not found in other languages, I disagree that users would find this extremely complex. If one understands classes and one understands interfaces, then abstract classes do not require a massive cognitive leap.

@jbondc
Copy link
Contributor

jbondc commented Jun 25, 2015

Objective thinking:
http://ocw.kfupm.edu.sa/ocw_courses/phase3/ICS201-Offering-052/Readings/p123-armstrong.pdf

What bothers me the most is the increasing and consistent sidestepping of the 'TS design rules' in favor of:

  1. Whatever aligns with the Microsoft Way does not require any justification

@jbondc
Copy link
Contributor

jbondc commented Jun 25, 2015

@kitsonk I must have missed it, when was abstract ever proposed?
http://wiki.ecmascript.org/doku.php?id=strawman:oldes6

@RyanCavanaugh
Copy link
Member

Here's the justification as I see it:

  1. abstract is extremely demanded. It's the highest-ranked thing (sorry, no upvotes on GitHub) from the CodePlex days that we haven't implemented yet. Issue Suggestion: abstract classes #6 is the only one we've ever cleaned up because there were too many 👍s to read the thread easily. The most common request we get from internal teams using TypeScript in large systems is abstract. It's one of the top five requests we get when meeting with external teams using TypeScript in large systems. The question on StackOverflow about "How do I do abstract in TypeScript?` is in the top 1% of most-voted TypeScript questions.
  2. abstract is highly precedented in virtually every language with a notion of classes. It's a common concept in OO and we can model it in a structural type system without any significant conceptual leaks.
  3. abstract is missing from the language. What I mean is that people are doing things to emulate abstract already and we are failing to provide a way to model that. It's trivial to find TypeScript repos with the exact code throw new Error("abstract");. It doesn't help us to plug our ears and say "la la la inheritance is terrible". You grow a language to meet the demands that exist (abstract and inheritance, in some cases), not the demands that you wish would exist (no one uses inheritance ever because it's terrible).
  4. abstract is unlikely to be a future ES proposal because it's essentially a type system feature. ES wouldn't really gain anything from adding abstract into the runtime because you can already emulate a late error with throw, and it would increase script startup time too much to make it an early error. And even if it did happen, it's very likely to have the same semantics as the ones described here -- in terms of runtime behavior, the design space has only one or two decisions.
  5. abstract is not difficult to reason about and I question the good faith of someone who would put that forth as a legitimate argument. I can explain this concept in the space of a tweet: "You can't construct an abstract class. Abstract methods are in abstract classes. Abstract methods lack bodies. #typescript #abstract". It doesn't require non-local reasoning. If you were stuck in a library with no books from the last dozen years, you could still read a doc written about how abstract works in C++, Java, C#, Scala, etc, and come away with a correct understanding of how it works in TypeScript.
  6. This feature matches every one of our design goals and non-goals. I am absolutely baffled that anyone would claim otherwise. Non-goal 1 is an important point in favor of this keyword, because we want to "use the behavior of JavaScript and the intentions of program authors as a guide for what makes the most sense in the language". We've seen that people fake abstract all the time (see point 3 above) by throwing errors or other approximations. I understand that not everyone is writing inheritance-based programs, but there are other programmers out there who are, and those people are frequently wishing this feature existed.

@DickvdBrink
Copy link
Contributor

Don't think it is fair to call It "the Microsoft way" because it is a really a much requested feature here on GitHub (#6 (comment)) and on CodePlex.

So some might not like it but others do. It is impossible to keep everyone happy after all.

@jbondc
Copy link
Contributor

jbondc commented Jun 25, 2015

@RyanCavanaugh Yes because there's no multiple inheritance in Java or C#?

If people prefer a better horse, fine. I'll take the car.

@jbondc
Copy link
Contributor

jbondc commented Jun 25, 2015

http://stackoverflow.com/questions/1991042/what-is-the-advantage-of-using-abstract-classes-instead-of-traits

Odersky et al's Programming in Scala recommends that, when you doubt, you use traits.

What's the Microsoft philosophy?

@sophiajt
Copy link
Contributor

It's not useful to argue the merits of inheritance in this thread. Inheritance is part of JavaScript. TypeScript supports JavaScript. Done.

Will TypeScript support other modeling methods, like composition via traits? I suspect it will at some point, especially since the JS committee is working on things like mixins. We'll support them as they land in JS.

Let's keep the conversation here to the merits of 'abstract' as a useful concept to help TypeScript support JavaScript's already existing inheritance functionality.

@jbondc
Copy link
Contributor

jbondc commented Jun 26, 2015

I see, so its not useful to discuss progress. Will be my last comment but will address the @RyanCavanaugh philosophy:

1.  abstract is extremely demanded. ... The most common request we get from internal teams 
using TypeScript in large systems is abstract.

It's called a selection bias.

  2. abstract is highly precedented in virtually every language with a notion of classes

There's something called progress and believe it applies to programming languages.

  3. abstract is missing from the language

Just because people have learned or been told to think a certain way and
grown into some habits doesn't mean we shouldn't challenge the status quo.

  4.  abstract is unlikely to be a future ES proposal

Cool we agree. Next up const, readonly, sealed right?
Nice goalpost move by making this a "type system" feature instead of an OO concept.

5. abstract is not difficult to reason about and I question the good faith of someone
6. This feature matches every one of our design goals and non-goals.
 I am absolutely baffled that anyone would claim otherwise

Good, not baffled that you are baffled. My thinking/ideology is different then yours, clearly I must be evil or of have some "ill-faith", burn the heretics!

@DanielRosenwasser
Copy link
Member

I'm not sure why you feel so impassioned against a feature you are sure you will never use.

Progress is a relative term, and while you may not find your domain is sufficiently serviced by a paradigm, consider the importance of being open minded in building a language - others have built well-thought-out designs using such paradigms and benefited greatly from them.

Furthermore, ad hominems like saying we are going with the "Microsoft way" is non-constructive (if not just insulting). Let's try to keep a more tempered discussion on this issue.

@kitsonk
Copy link
Contributor

kitsonk commented Jun 26, 2015

While I feel as impassioned about that wrangling purist-OO paradigms into ECMAScript is "bad", I agree with @DanielRosenwasser that laying it at the feet of "Microsoft way" diminishes all the hard work the TypeScript team have done. They strike me as a group of people who try their hardest to do the right thing, and try to limit external commercial imperatives that might influence them. abstract is not a Microsoft thing, it is a very very common OO paradigm. abstract does not break, or limit any of the features that I care about and upon reflection I agree with @RyanCavanaugh that it is every likely to conflict with ECMAScript, but largely, TC39 haven't proposed it. Other than promoting solving a problem in what I would consider an anti-pattern, which is simply a matter of opinion, there is nothing to this. It isn't being morally relativistic with the TypeScript design principles.

@jbondc
Copy link
Contributor

jbondc commented Jun 26, 2015

I've retracted some of my comments, no intent to insult anyone and the fantastic job by the TS team. Learned a lot from the compiler, continue to learn and its a real work of art. Got carried away by the "question the good faith of someone", apologies for that.

@DanielRosenwasser
Copy link
Member

No worries; text is a lossy format for tonality and intent 😄. Everyone in this discussion is well-intentioned. Even if it's not coming off that way, know that we understand your concerns and value them. Keep giving us feedback - it's a learning experience for us too.

(Also we appreciate the kind words guys!)

@Gaelan
Copy link

Gaelan commented Jun 26, 2015

Abstract support will never hurt anyone. If you don't want to use it, don't. Nobody's forcing you to use it. Assuming that this won't require re-architecting the project much (I doubt it will), I see absolutely no reason not to implement this feature.

@aozgaa aozgaa closed this as completed Jul 1, 2015
@Gaelan
Copy link

Gaelan commented Jul 1, 2015

@aozgaa Why the close?

@Gaelan
Copy link

Gaelan commented Jul 1, 2015

@Aleksey-Bykov Many developers think this is a useful feature. You can create a fork without abstract support, stay on an old version, or just don't use abstract support. Nobody is making you use it.

@zpdDG4gta8XKpMCd
Copy link

Just another thing to throw to garbage at linting and the rule for it is
darn simple. Nevermind
On Jul 1, 2015 7:55 PM, "Gaelan" [email protected] wrote:

@Aleksey-Bykov https://github.com/aleksey-bykov Many developers think
this is a useful feature. You can create a fork without abstract support,
stay on an old version, or just don't use abstract support. Nobody is
making you use it.


Reply to this email directly or view it on GitHub
#3578 (comment)
.

@zpdDG4gta8XKpMCd
Copy link

Algebraic data types and pattern matching is not even in the road map.
Shame shame shame. Upsetting
On Jul 1, 2015 8:07 PM, "Aleksey Bykov" [email protected] wrote:

Just another thing to throw to garbage at linting and the rule for it is
darn simple. Nevermind
On Jul 1, 2015 7:55 PM, "Gaelan" [email protected] wrote:

@Aleksey-Bykov https://github.com/aleksey-bykov Many developers think
this is a useful feature. You can create a fork without abstract support,
stay on an old version, or just don't use abstract support. Nobody is
making you use it.


Reply to this email directly or view it on GitHub
#3578 (comment)
.

@zpdDG4gta8XKpMCd
Copy link

Looks like C# is going to get them sooner than we here. Thats just plain
embarrassing
On Jul 1, 2015 8:21 PM, "Aleksey Bykov" [email protected] wrote:

Algebraic data types and pattern matching is not even in the road map.
Shame shame shame. Upsetting
On Jul 1, 2015 8:07 PM, "Aleksey Bykov" [email protected] wrote:

Just another thing to throw to garbage at linting and the rule for it is
darn simple. Nevermind
On Jul 1, 2015 7:55 PM, "Gaelan" [email protected] wrote:

@Aleksey-Bykov https://github.com/aleksey-bykov Many developers think
this is a useful feature. You can create a fork without abstract support,
stay on an old version, or just don't use abstract support. Nobody is
making you use it.


Reply to this email directly or view it on GitHub
#3578 (comment)
.

@bryanerayner
Copy link

@Aleksey-Bykov, I'd actually love to have mixins as a feature, but can't comprehend doing it without structured type support. Our codebase is far too big and our developers too few to do much meaningful development without the benefits typing brings.

Have you started submitting a proposal for mixins with typescript? If you haven't, are there good references to prior work where someone might begin working on fleshing that out? At this point if there's no proposals from TC39 which have stuck, it might as well start it's life here on the Typescript project

@CKGrafico
Copy link

@Gaelan You're totally right!

@NoelAbrahams
Copy link

👍 thank you. A right tool for the right job.

@danquirk
Copy link
Member

danquirk commented Jul 2, 2015

@Aleksey-Bykov C# operates under a completely different set of constraints than TypeScript does. We could love pure functional programming more than anyone but it doesn't change the rules we actually need to operate with as we design for the future (ie conforming to future ECMAScript standards). If you want an arbitrary set of language features/semantics that compile to JS there are a lot of options, but TypeScript isn't one of them. There are also web centric languages that have opted to add desirable expression level features divorced from ECMAScript standards. The value/success of these two divergent strategies is left as an exercise for the reader ;)

Suffice to say, we love designing new language features and want to keep adding stuff that makes everyone's lives easier, but it's simply not the case that we get to just pick our favorite features from Haskell, Smalltalk, etc and put them into TypeScript with no regard for future ECMAScript incompatibility they may/will cause.

@Yves57
Copy link

Yves57 commented Sep 3, 2015

Great job!
Just one question: it seems that properties cannot be abstract.
The code public abstract get myProp(): string; is not accepted.
Limitation or bug?

@mhegazy
Copy link
Contributor

mhegazy commented Sep 3, 2015

@Yves57 this is by design. there is no way to currently to distinguish between a property accessor and a property declaration, so a derived class can define a property declaration and would meet abstract constraints, but probably this is not what you intended by making the accessor abstract in the base.

@Yves57
Copy link

Yves57 commented Sep 4, 2015

@mhegazy To be more precise, my case is the following

interface IMyInterface { myProp: string; }
abstract class MyBase implements IMyInterface { abstract get myProp(): string; ......... }

But I understand that this is a specific case!

@denvned
Copy link
Contributor

denvned commented Sep 5, 2015

@Yves57, I've faced exactly same problem. Looks like this case isn't so rare...

It would be better if abstract class was allowed to miss fields from it's interface (both value properties and methods), like in other OOP languages.
So, this should be allowed:

interface A { p; m(); }
abstract class B implements A {}
class C extends B { get p() {...}; set p(v) {...}; m() {...} }

But currently it gives:

Error:(2, 16) TS2420: Class 'B' incorrectly implements interface 'A'. Property 'p' is missing in type 'B'.

@denvned
Copy link
Contributor

denvned commented Sep 5, 2015

Also I think that abstract value properties should be allowed in abstract classes (same way value properties are now allowed in interfaces):

abstract class A {
  abstract p;
}
class B extends A {
  get p() {...}
  set p(v) {...}
}

@mhegazy
Copy link
Contributor

mhegazy commented Sep 5, 2015

@denvned can you file separate issues to track the two requests, 1. abstract properties, and 2. missing property declaration in abstract class implementing interfaces.

@electricessence
Copy link

I'm trying to use this in WebStorm 11 with TS1.6... Not working?

@DanielRosenwasser
Copy link
Member

@electricessence WebStorm doesn't use our language service, so unless this is an issue you're seeing at compilations (i.e. not while editing) you should probably check in with them.

Though, it looks like they should support it: http://blog.jetbrains.com/webstorm/2015/09/webstorm-11-eap-142-4723/

@AJamesPhillips
Copy link

@bryanerayner +1 for:

@Aleksey-Bykov, I'd actually love to have mixins as a feature, but can't comprehend doing it without structured type support.

Have you started submitting a proposal for mixins with typescript? If you haven't, are there good references to prior work where someone might begin working on fleshing that out?

@zpdDG4gta8XKpMCd
Copy link

@AJamesPhillips
Copy link

@Aleksey-Bykov agreed, I shouldn't have said mixins as practically they share major downsides with multiple inheritance. For the moment I'm:

  • making sure my inheritance trees are as shallow as possible
  • using the is-a guideline
  • utility functions
  • And when all that fails because you have multiple base classes something "must" inherit from (and which utility functions can't deal with elegantly) then public and or private attributes set to helper functions and or class instances. If the helper functions and or class instances also need a reference to the instance then I set them in the constructor and pass this to them then.

Would be very interested to see composition / stamps / aspect / traits, in TypeScript. And thanks for the link to Dan Abramov's article.

@electricessence
Copy link

It works in 11.

From: Daniel Rosenwasser [mailto:[email protected]]
Sent: Tuesday, November 03, 2015 3:44 PM
To: Microsoft/TypeScript
Cc: electricessence
Subject: Re: [TypeScript] Proposal for Abstract Classes and Methods (#3578)

@electricessence https://github.com/electricessence WebStorm doesn't use our language service, so unless this is an issue you're seeing at compilations (i.e. not while editing) you should probably check in with them.

Though, it looks like they should support it: http://blog.jetbrains.com/webstorm/2015/09/webstorm-11-eap-142-4723/


Reply to this email directly or view it on GitHub #3578 (comment) .Image removed by sender.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Committed The team has roadmapped this issue Fixed A PR has been merged for this issue Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests