-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Suggestion: static constructors #265
Comments
👍 |
You can already accomplish this with a merged class/module: class MyClass {
static initialize() {
// Initialization
}
}
module MyClass {
MyClass.initialize();
} Or, for that matter, you can just have the call to initialize immediately follow the class declaration: class MyClass {
static initialize() {
// Initialization
}
}
MyClass.initialize(); |
Pleasure hearing from Mr. Hejlsberg... The only limitation I see there is that you can't make it private, whereas in my example you can :) |
👍 for class/module merge suggestion |
The merged class/module code requires that the developer remember to call The suggestion I believe is that given the following: class MyClass {
static initialized = false;
static constructor() {
MyClass.initialized = true;
}
} We get JavaScript var MyClass = (function () {
function MyClass() {
}
MyClass.initialized = false;
MyClass.__ctor = (function () {
MyClass.initialized = true;
})();
return MyClass;
})(); |
@NoelAbrahams Yes, good point about having to remember to call it in the merged class/module pattern. However, @ahejlsberg's code has the benefit that call to the static method is made at the very end when the class is completely loaded. I updated the suggestion above to reflect that. The static constructor syntax should only generate an anonymous function invocation at the end of the JavaScript class output. |
Privacy is a good point here, but it's worth pointing out that you can be a little "evil" to achieve the same goal without having to modify the language. ;) class C {
private static initialize(): void {
// do stuff
C.initialize = undefined;
}
}
(<any>C).initialize(); You can even replace But yes, here the user is still responsible with calling |
The suggested static constructor syntax remains to be superior IMO and has best of everything: 😌
|
Closing as Too Complex - we would need a more compelling use case since |
Anders brought up that we also need to be conservative here so that we don't misalign with the ES6 class proposal (which also lacks static constructors). |
👍 |
Agreed. Let's keep the pace with ES6. Though, I think I elaborated a little too much on this feature. I realized, specifically, moving the static constructor block to the end of the class was not necessary to defer its invocation. It is deferred anyway because it is in another function that is invoked when it is completely loaded. To test that: var MyClass = (function () {
function MyClass() {
}
(function () {
alert("static ctor invoked");
})();
return MyClass;
});// do not invoke yet
alert("class loaded");
// invoke
MyClass(); |
In case anyone is reaching this issue, you can also do it this way: class MyClass {
private static _constructor = (() => {
console.log('Static constructor');
})();
} This has the advantage of being a concise syntax not exposing any unnecessary variable. |
@aymericbeaumet That is my preferred solution so far and is also noted in the first post. |
Didn't catch you proposed the same solution! |
👍 Please do! However, a potential workaround would be:
|
Developers of TS, please, read about D language, where most problems with OOP are solved. For inspiration. Why i can not use "this" in "static" context? IMHO, "this" must point to current class (not to superclass). |
@nin-jin You can use Note that in any comparison to other languages you need to consider the somewhat unique constraints TypeScript operates with (as a superset of JavaScript and emitting clean, idiomatic JavaScript with minimal or no strange rewriting). Were we designing in a green field with only our own thoughts the language would look very different :) |
But what about inheritance? class A {
private options: {hello: number}
static constructor() {
console.log('called')
this.options = {hello: 123}
}
}
class B extends A {
} I would expect called to be logged twice. |
@felixfbecker Every static property is bind to the class. It cannot be inherited. So the static constructor should also follow this pattern to ensure a equal behavior. |
@PascalSenn static properties are inherited in ES6 and TypeScript. |
@felixfbecker Thats new for me. Didnt know that. C# doesnt support it, so i thought Typescript neither. |
@PascalSenn you can even do it in ES5: function SuperClass {}
SuperClass.staticProperty = 123;
function SubClass {}
Object.setPrototypeOf(SubClass, SuperClass); |
@RyanCavanaugh I don't think the merged module solution is anywhere near an approximation to a static constructor. It is still required that you call the static member whether you use merged modules or not. A static constructor would initialise automatically. |
It's too bad generic type references were dropped in static functions. I was using some static constructor style methods on some classes (similar to JoshMcCullough's post above) and now it's all broken. The only workaround was to convert the private static constructor methods to private instance methods and call them instead via the prototype from another static constructor method (or directly after the class). I didn't want to duplicate my class generic signature on my static method as well, that's just getting too silly. |
Hello, I hope Typescript will implement static constructors like this: It would solve "function properties" typing problem too: https://stackoverflow.com/questions/12766528/build-a-function-object-with-properties-in-typescript |
@Alphapage TypeScript supports many coming ES6+ changes today, best it can, and targeting such code will output code like this BTW: There's already a proposal here as well: https://github.com/tc39/ecma262/blob/master/workingdocs/callconstructor.md |
I'm not sure of the exact mechanics of some of the tree shakers out there, but won't some of these strategies disrupt the tree shakers? Calling a static method on the Type as a separate action outside of the class's IIFE (in ES5) may be seen as a reference to the type? Or containing some side effect that may not be possible to omit? Presumably being able to wrap some code inside of the class's ES5 iffe would been seen as more atomic with the definition of the type? |
@gmurray81 tree shaking is partial workaround of autoloaders absence. Better to use bundler that supports autoloading. MAM in example. |
@nin-jin even if you could just persuade everyone to use different technology in their projects to avoid a problem (some of us need to write library code for others to consume) there would still be an argument that it should be easy to make the creation/calling of the static cons atomic with the class creation. It seems like shoving an IIFE on the last defined static property of a type, as suggested above, might be the closest you can come with the syntax as it stands. It's a little ugly, though, comparatively. |
@aymericbeaumet The solution you provided may caused inspector report a 'unused variable' warning which cannot be silenced in webstorm... (I cannot write better one until now. Thinking.) |
A static constructor is a function that is run only once when the class is loaded. It can be used to initialize static class members and maybe as entry point to the application.
Suggested syntax is:
That would be same as the following:
Except that
__ctor
does not need to be assigned to the class in the output code, and only needs to be invoked in an anonymous function. Also compiler can check that no more than one static constructor is defined in a class.Update: Since this generates an Immediately-Invoked Function Expression (IIFE), compiler should make sure to move it to the end of the class definition in the output JavaScript.
TypeScript:
Expected JavaScript output:
Note that body of the static constructor is moved to the bottom and invoked.
The text was updated successfully, but these errors were encountered: