Inheritance of static properties

Topics: Language Specification
Dec 19, 2013 at 6:59 AM
I saw someone already asked about this in some discussion or issue but can't find it, so I start the new one.

Now the inheritance of classes applies inheritance for static fields too. So any derived class have same static fields as base class. Another words, if B is a class with static field s, and D is a class derived from the B then it have static field s with exactly same type.

It looks reasonable but it in case of JavaScript it produce a lot of problems.

Let's look at __extends function that is used by TS:
var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
So when we extend some class we copy all the static fields of base class to derived.
To keep type checking valid it produce the constraint that static fields of base classes can't change the type in derived class. So this code is not valid:
declare class B {
  static create(): B;
}
declare class D extends B {
  static create(a: number): D;
}
Class 'D' cannot extend class 'B': Types of static property 'create' of class 'D' and class 'B' are incompatible: Call signatures of types '(a: number) => D' and '() => B' are incompatible: Call signature expects 0 or fewer parameters.

But this use case used for many JS libraries/frameworks.
C# also allow to create overloads for static methods in derived classes.

I think TS should not copy static fields of base class object into derived class object.
Of course, it will produce that typeof D become incompatible with typeof B. But it can be so anyway, because signature of new can be different!

So I can't see any reason why static fields should be derived from base class. Developer always know what the base class of its class and know how to call any static member by using base class name.

To designers/developers of TS: please see how many errors it produced in DefinitelyTyped. It was worked in 0.9.1 and become not working in 0.9.5. For example error in three.js. Base class Curve have static field Utils and its derived class Shape also have Utils with different structure. So how we can describe it correctly?
Dec 19, 2013 at 7:10 AM
Dec 23, 2013 at 4:49 PM
Is anybody from TS team will answer to me?
Dec 24, 2013 at 1:51 AM
I'm totally agree for Igorbek's proposal.

Derived class inherit static member is not as common as JavaScript.
I had also thought of the inheritance mechanism that's as follows until you see the language specification.
var __extends = this.__extends || function (d, b) {
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
TypeScript can't access from non-static member to static member by keyword. (e.g. this.staticMember(); in non-static member
I used access to static member through the Base class name.
Dec 24, 2013 at 8:37 AM
Thanks a lot @vvakame!
In order to vote for proposal I created the work item.
Please vote if you support me.
Dec 26, 2013 at 4:12 PM
I am also generally in agreement with the views on this thread.

If I understand the position correctly, with respect to inheritance there should be no difference between static and instance methods.

However, when the base type has a property whose value is an object, the __extends copies a reference to that property, which is not the case when the property is a primitive:

    class Base { 
        static obj = { val: "foo" };
        static val = "foo";
        obj = { val: "foo" };
        val = "foo";
    }

    class Derived extends Base { }

    var sut = new Derived();

       // Act: Change values
        Base.obj.val = "bar";
        Base.val = "bar";
        sut.obj.val = "bar";
        sut.val = "bar";

        // Assert
       areEqual("bar", sut.obj.val, "Instance object references should refer to the base");
       areEqual("bar", sut.val, "Instance primitive values should refer to the base");
       areEqual("bar", Derived.obj.val, "Static object references should refer to the base");
       areEqual("foo", Derived.val, "Static primitive values should contain the value at declaration.");
I don't really like the fact that changing Base.obj.val also changes Derived.obj.val, but changing Base.val has no impact on Derived.val
Dec 30, 2013 at 9:48 PM
Edited Dec 30, 2013 at 9:48 PM
I've updated the issue [ https://typescript.codeplex.com/workitem/2047 ] tracking this with the latest outcome of investigations into addressing this.