{"action":"created","issue":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/14600","repository_url":"https://api.github.com/repos/Microsoft/TypeScript","labels_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/14600/labels{/name}","comments_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/14600/comments","events_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/14600/events","html_url":"https://github.com/Microsoft/TypeScript/issues/14600","id":213566462,"number":14600,"title":"Suggestion: Add abstract static methods in classes and static methods in interfaces","user":{"login":"vyshkant","id":4893820,"avatar_url":"https://avatars1.githubusercontent.com/u/4893820?v=4","gravatar_id":"","url":"https://api.github.com/users/vyshkant","html_url":"https://github.com/vyshkant","followers_url":"https://api.github.com/users/vyshkant/followers","following_url":"https://api.github.com/users/vyshkant/following{/other_user}","gists_url":"https://api.github.com/users/vyshkant/gists{/gist_id}","starred_url":"https://api.github.com/users/vyshkant/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vyshkant/subscriptions","organizations_url":"https://api.github.com/users/vyshkant/orgs","repos_url":"https://api.github.com/users/vyshkant/repos","events_url":"https://api.github.com/users/vyshkant/events{/privacy}","received_events_url":"https://api.github.com/users/vyshkant/received_events","type":"User","site_admin":false},"labels":[{"id":373477802,"url":"https://api.github.com/repos/Microsoft/TypeScript/labels/Awaiting%20More%20Feedback","name":"Awaiting More Feedback","color":"556677","default":false},{"id":113971155,"url":"https://api.github.com/repos/Microsoft/TypeScript/labels/Suggestion","name":"Suggestion","color":"006b75","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":36,"created_at":"2017-03-11T23:06:29Z","updated_at":"2018-03-23T15:07:53Z","closed_at":null,"author_association":"NONE","body":"As a continuation #2947 issue, which allows the `abstract` modifier on method declarations but disallows it on static methods declarations, I suggest to expand this functionality to static methods declarations by allowing `abstract static` modifier on method declarations.\r\n\r\nThe related problem concerns `static` modifier on interface methods  declaration, which is disallowed.\r\n\r\n# 1. The problem\r\n\r\n## 1.1. Abstract static methods in abstract classes\r\n\r\nIn some cases of using the abstract class and its implementations I may need to have some class-dependent (not instance-dependent) values, that shoul be accessed within the context of the child class (not within the context of an object), without creating an object. The feature that allows doing this is the `static` modifier on the method declaration.\r\n\r\nFor example (example 1):\r\n```ts\r\n\r\nabstract class AbstractParentClass {\r\n}\r\n\r\nclass FirstChildClass extends AbstractParentClass {\r\n\r\n    public static getSomeClassDependentValue(): string {\r\n        return 'Some class-dependent value of class FirstChildClass';\r\n    }\r\n}\r\n\r\nclass SecondChildClass extends AbstractParentClass {\r\n\r\n    public static getSomeClassDependentValue(): string {\r\n        return 'Some class-dependent value of class SecondChildClass';\r\n    }\r\n}\r\n\r\nFirstChildClass.getSomeClassDependentValue(); // returns 'Some class-dependent value of class FirstChildClass'\r\nSecondChildClass.getSomeClassDependentValue(); // returns 'Some class-dependent value of class SecondChildClass'\r\n\r\n```\r\n\r\nBut in some cases I also need to acces this value when I only know that the accessing class is inherited from AbstractParentClass, but I don't know which specific child class I'm accessing. So I want to be sure, that every child of the AbstractParentClass has this static method.\r\n\r\nFor example (example 2):\r\n```ts\r\n\r\nabstract class AbstractParentClass {\r\n}\r\n\r\nclass FirstChildClass extends AbstractParentClass {\r\n\r\n    public static getSomeClassDependentValue(): string {\r\n        return 'Some class-dependent value of class FirstChildClass';\r\n    }\r\n}\r\n\r\nclass SecondChildClass extends AbstractParentClass {\r\n\r\n    public static getSomeClassDependentValue(): string {\r\n        return 'Some class-dependent value of class SecondChildClass';\r\n    }\r\n}\r\n\r\nabstract class AbstractParentClassFactory {\r\n\r\n    public static getClasses(): (typeof AbstractParentClass)[] {\r\n        return [\r\n            FirstChildClass,\r\n            SecondChildClass\r\n        ];\r\n    }\r\n}\r\n\r\nvar classes = AbstractParentClassFactory.getClasses(); // returns some child classes (not objects) of AbstractParentClass\r\n\r\nfor (var index in classes) {\r\n    if (classes.hasOwnProperty(index)) {\r\n        classes[index].getSomeClassDependentValue(); // error: Property 'getSomeClassDependentValue' does not exist on type 'typeof AbstractParentClass'.\r\n    }\r\n}\r\n\r\n```\r\n\r\nAs a result, the compiler decides that an error occurred and displays the message: Property 'getSomeClassDependentValue' does not exist on type 'typeof AbstractParentClass'.\r\n\r\n## 1.2. Static methods in interfaces\r\n\r\nIn some cases, the interface logic implies that the implementing classes must have a static method, that has the predetermined list of parameters and returns the value of exact type.\r\n\r\nFor example (example 3):\r\n```ts\r\ninterface Serializable {\r\n    serialize(): string;\r\n    static deserialize(serializedValue: string): Serializable; // error: 'static' modifier cannot appear on a type member.\r\n}\r\n```\r\n\r\nWhen compiling this code, an error occurs: 'static' modifier cannot appear on a type member.\r\n\r\n# 2. The solution\r\n\r\nThe solution to both problems (1.1 and 1.2) is to allows the `abstract` modifier on static method declarations in abstract classes and the `static` modifier in interfaces.\r\n\r\n# 3. JS implementaion\r\n\r\nThe implementation of this feature in JavaScript should be similar to the implementation of interfaces, abstract methods and static methods.\r\n\r\nThis means that:\r\n1. Declaring abstract static methods in an abstract class should not affect the representation of the abstract class in the JavaScript code.\r\n2. Declaring static methods in the interface should not affect the representation of the interface in JavaScript code (it is not present).\r\n\r\nFor example, this TypeScript code (example 4): \r\n\r\n```ts\r\n\r\ninterface Serializable {\r\n    serialize(): string;\r\n    static deserialize(serializedValue: string): Serializable;\r\n}\r\n\r\nabstract class AbstractParentClass {\r\n    public abstract static getSomeClassDependentValue(): string;\r\n}\r\n\r\nclass FirstChildClass extends AbstractParentClass {\r\n\r\n    public static getSomeClassDependentValue(): string {\r\n        return 'Some class-dependent value of class FirstChildClass';\r\n    }\r\n}\r\n\r\nclass SecondChildClass extends AbstractParentClass implements Serializable {\r\n\r\n    public serialize(): string {\r\n        var serialisedValue: string;\r\n        // serialization of this\r\n        return serialisedValue;\r\n    }\r\n\r\n    public static deserialize(serializedValue: string): SecondChildClass {\r\n        var instance = new SecondChildClass();\r\n        // deserialization\r\n        return instance;\r\n    }\r\n\r\n    public static getSomeClassDependentValue(): string {\r\n        return 'Some class-dependent value of class SecondChildClass';\r\n    }\r\n}\r\n```\r\n\r\nshould be compiled to this JS code:\r\n```js\r\nvar AbstractParentClass = (function () {\r\n    function AbstractParentClass() {\r\n    }\r\n    return AbstractParentClass;\r\n}());\r\n\r\nvar FirstChildClass = (function (_super) {\r\n    __extends(FirstChildClass, _super);\r\n    function FirstChildClass() {\r\n        return _super !== null && _super.apply(this, arguments) || this;\r\n    }\r\n    FirstChildClass.getSomeClassDependentValue = function () {\r\n        return 'Some class-dependent value of class FirstChildClass';\r\n    };\r\n    return FirstChildClass;\r\n}(AbstractParentClass));\r\n\r\nvar SecondChildClass = (function (_super) {\r\n    __extends(SecondChildClass, _super);\r\n    function SecondChildClass() {\r\n        return _super !== null && _super.apply(this, arguments) || this;\r\n    }\r\n    SecondChildClass.prototype.serialize = function () {\r\n        var serialisedValue;\r\n        // serialization of this\r\n        return serialisedValue;\r\n    };\r\n    SecondChildClass.deserialize = function (serializedValue) {\r\n        var instance = new SecondChildClass();\r\n        // deserialization\r\n        return instance;\r\n    };\r\n    SecondChildClass.getSomeClassDependentValue = function () {\r\n        return 'Some class-dependent value of class SecondChildClass';\r\n    };\r\n    return SecondChildClass;\r\n}(AbstractParentClass));\r\n```\r\n\r\n# 4. Relevant points\r\n\r\n- The declaration of an abstract static method of an abstract class should be marked with `abstract static` modifier\r\n- The implementation of abstract static method of an abstract class shoul be marked with `abstract static` or `static` modifier\r\n- The declaration of static method of an interface should be marked with `static` modifier\r\n- The implementation of static method of an interface shoul be marked with `static` modifier\r\n\r\nAll the other properties of `abstract static` modifier should be inherited from `abstract` and `static` modifiers properties.\r\n\r\nAll the other properties of `static` interface method modifier should be inherited from the interface methods and `static` modifier properties.\r\n\r\n# 5. Language Feature Checklist\r\n\r\n* Syntactic\r\n  * _What is the grammar of this feature?_ - **The grammar of this feature is `abstract static` modifier of an abstract class method and `static` modifier of an interface method.**\r\n  * _Are there any implications for JavaScript back-compat? If so, are they sufficiently mitigated?_ - **There is no any implications for JavaScript back-compat.**\r\n  * _Does this syntax interfere with ES6 or plausible ES7 changes?_ - **This syntax does not interfere with ES6 or plausible ES7 changes.**\r\n* Semantic\r\n  * _What is an error under the proposed feature?_ - **Now there are errors compiling `abstract static` modifier of an abstract class method and `static` modifier of an interface method. Proposed feature have to fix these errors.**\r\n  * _How does the feature impact subtype, supertype, identity, and assignability relationships?_ - **The feature does not impact subtype, supertype, identity, and assignability relationships.**\r\n  * _How does the feature interact with generics?_ - **The feature does not interact with generics.**\r\n* Emit\r\n  * _What are the effects of this feature on JavaScript emit?_ - **There are no effects of this feature on JavaScript emit.**\r\n  * _Does this emit correctly in the presence of variables of type ‘any’?_ - **Yes.**\r\n  * _What are the impacts to declaration file (.d.ts) emit?_ - **There is no impacts to declaration file.**\r\n  * _Does this feature play well with external modules?_ - **Yes.**\r\n* Compatibility\r\n  * _Is this a breaking change from the 1.0 compiler?_ - **Probably yes, 1.0 compiler will not be able to compile the code implementing this feature.** \r\n  * _Is this a breaking change from JavaScript behavior?_ - **No.**\r\n  * _Is this an incompatible implementation of a future JavaScript (i.e. ES6/ES7/later) feature?_ - **No.**\r\n* Other\r\n  * _Can the feature be implemented without negatively affecting compiler performance?_ - **Probably yes.**\r\n  * _What impact does it have on tooling scenarios, such as member completion and signature help in editors?_ - **Probably it does not have any impact of this type.**"},"comment":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/comments/375696066","html_url":"https://github.com/Microsoft/TypeScript/issues/14600#issuecomment-375696066","issue_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/14600","id":375696066,"user":{"login":"weeco","id":23424570,"avatar_url":"https://avatars3.githubusercontent.com/u/23424570?v=4","gravatar_id":"","url":"https://api.github.com/users/weeco","html_url":"https://github.com/weeco","followers_url":"https://api.github.com/users/weeco/followers","following_url":"https://api.github.com/users/weeco/following{/other_user}","gists_url":"https://api.github.com/users/weeco/gists{/gist_id}","starred_url":"https://api.github.com/users/weeco/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/weeco/subscriptions","organizations_url":"https://api.github.com/users/weeco/orgs","repos_url":"https://api.github.com/users/weeco/repos","events_url":"https://api.github.com/users/weeco/events{/privacy}","received_events_url":"https://api.github.com/users/weeco/received_events","type":"User","site_admin":false},"created_at":"2018-03-23T15:07:53Z","updated_at":"2018-03-23T15:07:53Z","author_association":"NONE","body":"Agreed this should be allowed. Following simple use case would benefit from abstract static methods:\r\n\r\n```ts\r\nexport abstract class Component {\r\n  public abstract static readFrom(): Component;\r\n}\r\n\r\n// I want to force my DeckComponent class to implement it's own static ReadFrom method\r\nexport class DeckComponent extends Component {\r\n  public cardIds: number[];\r\n\r\n  constructor(cardIds: number[]) {\r\n    this.cardIds = cardIds;\r\n  }\r\n\r\n  public static readFrom(buffer: ByteBuffer): DeckComponent {\r\n    const cardIds: number[] = [...];\r\n    return new DeckComponent(cardIds);\r\n  }\r\n}\r\n```"}}
{"actor":{"display_login":"weeco"}}