TypeScript - should it be? (where is == global reach)

I am using an Angular application to use TypeScript, but this is a general TypeScript question, not Angular. Angular js files are located along the lines:

(function () { var app = angular.module('myModule', []); app.controller('myController', ['$scope', function ($scope) { $scope.myNewProperty = "Bob"; } ]); })(); 

And I converted this to a beautiful TypeScript class syntax:

 class myController { constructor($scope) { $scope.myNewProperty = "Bob"; } } angular.module('myModule', []).controller("myController", myController); 

Everything works fine, except that the generated JS is not wrapped according to the JS module template (i.e. in an external anonymous function):

 var myController = (function () { app.controller('myController', ['$scope', function ($scope) { $scope.myNewProperty = "Bob"; } ]); })(); var app = angular.module('myModule', []); 

So myController is now global. If I put the class in a TypeScript module, then js generates the module name as a global variable:

 var TsModule; (function (TsModule) { var myController = (function () { app.controller('myController', ['$scope', function ($scope) { $scope.myNewProperty = "Bob"; } ]); })(); var app = angular.module('myModule', []); })(TsModule || (TsModule = {})); 

How to stop TypeScript global area pollution this way? I just want it all to be on a good local scale. I saw him say elsewhere: "just go back to the old JS syntax" (i.e. TypeScript class). How to define an AngularJS service using a TypeScript class that does not pollute the global scope?

But we all use TypeScript / is / class syntax. Is TypeScript a disagreement with any (sensible) JS programmer who knows that he is not global?

+6
source share
4 answers

You can just wrap your class inside module

The module itself will be global, but if you do not export this class, you have little to worry about polluting the global area with a single module name.

So this is TypeScript:

 module MyModule { class MyClass { constructor(){} } } 

The following JS will print:

 var MyModule; (function (MyModule) { var MyClass = (function () { function MyClass() { } return MyClass; })(); })(MyModule || (MyModule = {})); 
+4
source

Quick update

In recent versions of TypeScript, you can insert a class inside IIFE:

 (() => { class Example { } })(); 

Resulting result:

 (function () { var Example = (function () { function Example() { } return Example; }()); })(); 

Original answer

You can avoid adding to the global scope using a module template such as AMD or CommonJS. When you use any of them, each TypeScript file is considered an external module and stored outside the global scope.

This example removes Angular for the purposes of the example, but while RequireJS adds the define method to the global, none of your codes fit in this area.

Mymodule.ts

 export class myController { constructor($scope) { $scope.myNewProperty = "Bob"; } } 

app.ts

 import MyModule = require('MyModule'); var controller = new MyModule.myController(''); 

HTML

 <script src="Scripts/require.js" data-main="app.js"></script> 

What app.js looks like:

 define(["require", "exports", 'MyModule'], function (require, exports, MyModule) { var controller = new MyModule.myController(''); }); 

Alternatively ... as you know ... you can still implement all this using the JavaScript that you are already using, if you want - you will still get automatic completion and type checking, which are the main benefits, even if you aren Getting classes .

+2
source

Josh is right. Use the module. It is also probably a good idea to use grunt or gulp uglifyer, which has the ability to wrap your application during shutdown during build.

This is not an answer to your question, but a bigger suggestion.

In a side note, consider this syntax for controllers

 module myModule { // We export the class so that we can access its interface in tests. // The build time gulp or grunt uglify will wrap our app in a closure // so that none of these exports will be available outside the app. export class MyController { myNewProperty = "bob"; // Next we will use Angulars $inject annotation to inject a service // into our controller. We will make this private so that it can be // used internally. static $inject = ['someService']; constructor(private someService: ng.ISomeService) {} // we can access our class members using 'this' doSomething() { this.someService.doSomething(this.myNewProperty); } } angular.module('app').controller('MyController', MyController); } 

Along with this syntax, you should use the controllerAs syntax.

+1
source

Just like in JavaScript, you can completely avoid pollution of the namespace by wrapping your declarations inside the function expression immediately displayed.

So, the original JavaScript:

 (function () { var app = angular.module('myModule', []); app.controller('myController', ['$scope', function ($scope) { $scope.myNewProperty = "Bob"; } ]); })(); 

becomes the following TypeScript:

 (function () { class MyController { static $inject = ['$scope']; contructor($scope: ng.IScope & { myNewProperty: string }) { $scope.myNewProperty = 'Bob'; } } angular.module('myModule', []) .controller('MyController', MyController); })(); 

Note that this does not introduce any names into the surrounding volume. Actually, the original JavaScript is perfectly valid TypeScript, but it does not use TypeScript. Also note that I changed the style a bit.

In any case, if you do not use modules with a module loader, such as RequireJS, SystemJS, or whatever you have, you can still avoid namespace pollution by following the proven and true IIFE pattern. This is my recommendation.

0
source

Source: https://habr.com/ru/post/979406/


All Articles