Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript closures - an "almost" solution

One of my biggest bugbears with TypeScript is the fact that it compiles all methods (regardless of the access modifier) to the prototype.

Example

class Example {
    public getString(): string {
        return "Hello World";
    }

    private getNumber(): number {
        return 123;
    }
}

As we know, the access modifiers are only checked at compilation, thus ignored by the emitted JavaScript. One way JavaScript developers have learned to mitigate this is to use closures (okay, we know there are performance penalties to pay with closures, but I believe there are cases where closures are absolutely necessary).

Example

var Example = (function () {
    function Example() {
        this.getString = function () {
            return "Hello World";
        }

        var getNumber = function() {
            return 123;
        }
    }

    return Example;
})();

The above example respects the public/private access.

I've worked out that by using lambda syntax we can declare public closure methods within TypeScript.

Example

class Example {
    getString = (): string => {
        return "Hello World";
    }
}

It's not particularly pretty, but it works.

What I would like to know is: How would I declare private closures in TypeScript?

Example

class Example {

    // TypeScript doesn't like this!
    var getNumber = (): number => {
        return 123;
    }
}

See more on this bugbear here: https://github.com/Microsoft/TypeScript/issues/2940

like image 225
Matthew Layton Avatar asked Jun 17 '15 10:06

Matthew Layton


2 Answers

TypeScript brings types and accessors to ES6 (and it checks both statically). The class keyword in TypeScript is the standard class keyword from ES6. There are no private closures in ES6 classes. This syntax is not valid in ES6:

class Example {
    var v = /* ... */; // invalid in ES6
}

If you need to declare a closure that encapsulates variables, you should use the classic JavaScript way. I strongly suggest to takes advantage of the TS interfaces:

interface NamedObject {
    getName(): string;
}

let createNamedObject = function (name = 'John'): NamedObject {
    return {
        getName: function () {
            return name;
        }
    };
};

let obj: NamedObject = createNamedObject();

If you really want to make class methods with closures, you can do this:

class BadPerformance {
    public getName: () => string;

    constructor(name = 'John') {
        this.getName = () => {
            return name;
        };
    }
}
like image 50
Paleo Avatar answered Oct 02 '22 16:10

Paleo


As we know, the access modifiers are only checked at compilation, thus ignored by the emitted JavaScript.

That's because privacy in this context is privacy of the API from other developer. If you want them to know that the method is private - provide them with a .d.ts file so their editor can know that or don't document it in the API Documentation.

In JavaScript the documentation is often regarded as the API.

What I would like to know is: How would I declare private closures in TypeScript?

You can create functions in the constructor which would declare them on the instance and not on the prototype. This would allow you to use a closure - it also goes against prototypical inheritance and the nature of TypeScript and JavaScript.

like image 31
Benjamin Gruenbaum Avatar answered Oct 02 '22 17:10

Benjamin Gruenbaum