20

I know that we can declare a Static Variable or Function within a Class like this

class SomeClass(){
  static foo = 1;
  static fooBar(){ 
    return ++SomeClass.foo;
  }
}

Is there any way to declare a Static Local Variable directly inside the function something like this ?

class SomeClass(){
  fooBar(){
    static foo = 1;
    return ++this.foo;
  }
}

4 Answers 4

17

This isn't possible. You can declare the static in the class, but not in a function body.

Sign up to request clarification or add additional context in comments.

4 Comments

I would like to complain about this. Doesn't it encourage poor design? Particular for mouse handling I need certain flags to be set during mouse down and then viewed in mouse move. Surely those should be scoped to a method -- NOT to the component.
It's really unclear how you would downlevel a method-level static variable. It can't be on the closure because method closures are shared between class instances, and it can't be on the class instance because there's no way to compute a "safe" name which is not known to be stomped on by derived classes (or even base classes).
As shown by @Trass3r below, overriding the function on each instance could be a solution to implement this feature wise. My comment on basarat 's answer states, why a per-instance static would be useful as well, not sure though, how to name both of them.
@Ryan I agree it would be nice to have function local static for encapsulation, like old C did. TS could store the static in the class, but scope it to just the function (like private variable is stored in instance, but scoped to class). However, TS would have to think of a name for the static class member, and it would be difficult to guarantee no collisions with function-scope statics in (e.g.) derived classes. So I guess TS designers just said "no".
11

Is there any way to declare a Static Local Variable directly inside the function something like this

There is no special syntax for it. But if you want a stateful function the pattern is covered here : https://github.com/basarat/typescript-book/blob/master/docs/tips/statefulFunctions.md

For your example:

class SomeClass {
    fooBar = (new class {
        foo = 1;
        inc = () => this.foo++;
    }).inc
}

let foo = new SomeClass();
console.log(foo.fooBar()); // 1
console.log(foo.fooBar()); // 2

4 Comments

Basarat, @Ryan-Cavanaugh but why isn't it possible ? Is this because of logical constraints or the authors just didn't implement for some reason ?
@A.Singh because TypeScript is not perfect. But its pretty darn awesome still : medium.com/@basarat/… And all language features start at -100
See @realh's answer below for why the above is wrong.
+1 - despite the discussion about static it's a useful feature. Actually there should be both: variables that are static across all calls of the function across all instances of the class and variables that are "somewhat static" across all calls of the function per instance of the class.
4

I think there's a problem in @basarat's answer. Add this:

let bar = new SomeClass();
console.log(bar.fooBar());

The result is 1 because fooBar is not a method, but a field that happens to be a function. Therefore each instance of SomeClass has its own closure for fooBar with its own distinct foo.

I think that to truly emulate a static local variable as in C++, the answer should be 3, because the one method and one foo are shared by all instances. To do this in Typescript you could instead define fooBar after the rest of the class:

SomeClass.prototype.fooBar = (function() {
    let foo = 1;
    function fooBar() {
        return foo++;
    }
    return fooBar;
})();

I've also used a different idiom to create the closure, avoiding the introduction of a new class and not using arrow notation. In case fooBar ever needs to access members of an instance, now there won't be any confusion over what this refers to.

If necessary I guess you could also include a dummy definition of fooBar() in the class body to satisfy type checking; the subsequent external definition should simply overwrite it.

Comments

2

Improving on @realh's answer I was able to solve it all inside the class:

SomeClass {
...
    fooBar = (function () {
        let foo = 1;
        function fooBar(this: SomeClass) {
            return foo++;
        }
        return fooBar;
    })();

The this parameter is the crucial piece to access the class fields.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.