-
Notifications
You must be signed in to change notification settings - Fork 109
Warn when enumerating static properties #121
Comments
Minimal repro (I think?) Input: class Foo {
static bar = 3;
}
[Foo].map(x => x.bar); produces: var Foo = (function () {
function Foo() {
}
Foo.bar = 3;
return Foo;
}());
[Foo].map(function (x) { return x.bar; }); But you can't use The hard question is, how do we detect when you're doing this! |
Yes, see here, section about object flattening. This should really be an error/warning in Closure Compiler. Would you mind filing something against them, too, @DavidSouther? |
This also means I can't do this for my parameterized tests:
Full example: http://goo.gl/xATcQc Darn. :( |
|
....and it's closed, as "not feasible", with |
So I think what we could do is check, when you access foo.bar, whether .bar is a static property on a class and if so, whether it has been annotated with @nocollapse. Maybe. Seems like kind of a stretch. |
If I'm understanding you, that heuristic is Static class properties that get accessed in the compilation unit get marked @nocollapse? |
Sorry it was pretty terse. :) The Closure rules are:
So what I was suggesting is that for each expression that looks like The hard thing is something like this, which is currently legal TS but bad Closure: class Foo {
x: number;
static y: number;
}
interface HasY {
y: number;
}
let z: HasY = Foo;
z.y; I think the only way to protect from this is to make Foo somehow not implement the HasY interface (unless, again |
Maybe collect all properties that are ever accessed in a non-static way, Evan Martin notifications@github.com schrieb am Mi., 8. Juni 2016, 08:10:
|
Here's the idea I alluded to at the end of my last comment:
Now the class won't match the HasY interface I mentioned above unless you @nocollapse it but otherwise statics behave as before. The tricky part is #2, especially across d.ts files... |
Yes, (2) is going to be hard in the general case.
I think it helps to think about this as a type system feature: we're adding
a feature to the type system where you may not use static properties to
satisfy an instance level type. Each property of a type would carry an
addition flag "isStatic", and on assignment of two values, their property
types have to match, but so do their "isStatic" flags, too. Static fields
with a @nocollapse would have isStatic = false (which clearly is a misnomer
here, I hope it's still understandable). The analogy doesn't quite match -
you cannot construct types that demand an "isStatic = true".
I think this would not have to work across .d.ts files - any type will
always demand only non-isStatic fields, i.e. you can never construct a
reference to a value that contains non-isStatic fields. On the .d.ts level,
you would thus never need to express types that have isStatic = true on any
member.
Thinking of it like this, tsickle would have to inspect every type
compatibility check (including passing values to function calls, using
types as generic type arguments), and error if the RHS has any isStatic
properties that appear in the LHS. So, still hard, but maybe somewhat
tractable?
Another problem is that we have some language constructs like decorators
that might be hard to keep track of, and of course there's <any> messing
things up.
|
Another thought: always use @nocollapse and tell people to not use static methods unless they really need the method to be on the class. (You can otherwise make a top-level function.) |
I do wish the Closure Compiler did a better job at warning people about this. I'm not that familiar with the TypeScript type system, just looking around there doesn't seem to be a way of expressing a type that is a reference a class itself? If there was such a type, you could emit a warning for all property accesses to an object of that type. It definitely wouldn't catch everything.
Could you detect here that you are exposing a static property on to a instance type and throw a warning/error? The @nocollapse everywhere and documenting the code size implications of using static class properties SGTM. |
Since writing
is equivalent to
except that to access one you write Another way of saying this is that "static" is a TS feature and we can just decide it means "never collapse". Within Google we have a lint warning about overuse of static mostly because it's a pet peeve of mine, unrelated to all of this. |
I don't think "static" is just a typescript feature. I think its part of the ES6 spec https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-2&targets=&browsers=&builtIns=false&debug=false&code=class%20A%20%7B%0A%20%20static%20someMethod()%20%7B%7D%0A%7D |
You are right, sorry. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static indicates that maybe it's not supported in Safari which seems surprising and maybe just wrong (?) |
In Typescript, I can have a static class property:
Typescript happily compiles this to
(Static properties aren't valid ES2015: http://www.ecma-international.org/ecma-262/6.0/#sec-class-definitions)
Then, I do this weird thing:
Where I map over all the classes I intend to instantiate, and prepare their modules.
JSCompiler then helpfully minimizes all this to
Happily throwing away all the unused properties!
I can add exports:
Which Typescript puts in a sane place:
Which JSCompiler ignores.
I can get away with using the fully qualified form:
Becomes
Please emit a warning in the property enumeration case.
The text was updated successfully, but these errors were encountered: