Skip to content

Static class properties should be inherited #1900

@sophiebits

Description

@sophiebits

In ES6 classes, static properties should be inherited. That is,

class Foo {
}
Foo.x = 5;

class Bar extends Foo {
}

console.log(Bar.x);

should log "5". This can be done by looping over the properties and copying, but that's subpar because updating the static properties on the superclass should update them on the subclass too. Babel sets __proto__ to achieve this:

https://github.com/babel/babel/blob/554fda00c179eea72121cafe4b90fac85c1bb244/packages/babel/src/transformation/templates/helper-inherits.js#L13

It doesn't look like the ES5 emitter makes any attempt to get the same behavior:

/** Generates the JS constructor for a class, ES5 style. */
private def genES5Constructor(tree: LinkedClass): js.Tree = {
implicit val pos = tree.pos
val className = tree.name.name
val isJSClass = tree.kind.isJSClass
def makeInheritableCtorDef(ctorToMimic: js.Tree) = {
js.Block(
js.DocComment("@constructor"),
envFieldDef("h", className, js.Function(Nil, js.Skip())),
js.Assign(envField("h", className).prototype, ctorToMimic.prototype)
)
}
val ctorFun = if (!isJSClass) {
val superCtorCall = tree.superClass.fold[js.Tree] {
js.Skip()
} { parentIdent =>
js.Apply(
js.DotSelect(encodeClassVar(parentIdent.name), js.Ident("call")),
List(js.This()))
}
val fieldDefs = genFieldDefs(tree)
js.Function(Nil, js.Block(superCtorCall :: fieldDefs))
} else {
genConstructorFunForJSClass(tree)
}
val typeVar = encodeClassVar(className)
val docComment = js.DocComment("@constructor")
val ctorDef = envFieldDef("c", className, ctorFun)
val chainProto = tree.superClass.fold[js.Tree] {
js.Skip()
} { parentIdent =>
val (inheritedCtorDef, inheritedCtorRef) = if (!isJSClass) {
(js.Skip(), envField("h", parentIdent.name))
} else {
val superCtor = genRawJSClassConstructor(
linkedClassByName(parentIdent.name))
(makeInheritableCtorDef(superCtor), envField("h", className))
}
js.Block(
inheritedCtorDef,
js.Assign(typeVar.prototype, js.New(inheritedCtorRef, Nil)),
genAddToPrototype(className, js.Ident("constructor"), typeVar)
)
}
val inheritableCtorDef =
if (isJSClass) js.Skip()
else makeInheritableCtorDef(typeVar)
js.Block(docComment, ctorDef, chainProto, inheritableCtorDef)
}

This means scala-js does not work with React 0.14+ which checks for a static flag on classes extending React.Component:

http://stackoverflow.com/questions/32509891/warning-react-component-classes-must-extend-react-component-0-14-rc1

Metadata

Metadata

Assignees

No one assigned

    Labels

    wontfixWe decided not to fix this issue/not implement that feature request.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions