2014-12-10 10 views
6

Konwertuję aplikację Angular, aby używać TypeScript, ale jest to ogólne pytanie TypeScript, a nie Angular. kątowe pliki js są wzdłuż linii:TypeScript - ona musi to mieć? (gdzie to == globalny zasięg)

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

A ja konwertowane że do pięknej klasy maszynopis składnię:

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

angular.module('myModule', []).controller("myController", myController); 

Wszystko działa dobrze, z wyjątkiem wygenerowanym JS nie jest pakowane zgodnie z JS wzór modułu (tj. w zewnętrznej anonimowej funkcji):

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

var app = angular.module('myModule', []); 

Więc myController jest teraz globalny. Jeśli mogę umieścić klasę w module maszynopis, to js generuje z nazwą modułu jako zmienną globalną:

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

    var app = angular.module('myModule', []); 
})(TsModule || (TsModule = {})); 

Jak zatrzymać maszynopis zanieczyszczających zasięg globalny w ten sposób? Chcę tylko, żeby wszystko było zapakowane w miły lokalny zasięg. Widziałem, jak to zostało powiedziane w innym miejscu: "po prostu wróć do starej składni JS" (tzn. Bez klasy TypeScript). How can I define an AngularJS service using a TypeScript class that doesn't pollute the global scope?

Ale naszym celem jest użycie składni języka TypeScript/is/the class. Czy TypeScript jest w sprzeczności z jakimkolwiek (rozsądnym) programistą JS, który wie, że nie chce działać globalnie?

+0

Minęło trochę czasu odkąd użyłem TypeScript, więc mógłbym być wyłączony na tym, ale czy próbowałeś owijać powyższy kod TypeScript w natychmiast wywoływaną funkcję lambda? '(() => { // Kod tutaj ... })();' –

+0

Dostaję frustrację, ale używanie pojedynczej, dobrze zdefiniowanej nazwy modułu dla wszystkich plików praktycznie nie powoduje zanieczyszczenia globalnego zasięgu. Będzie tworzyć pojedynczą zmienną na globalnym zasięgu, a nawet wtedy, jeśli nie eksportujesz swoich klas, to nigdy nie będzie to więcej niż pusty obiekt. To drobny problem. – Josh

+1

Po prostu FYI (możesz już wiedzieć) wyrażeń klas nadchodzi w TS następnie, który pozwoli im w IIFE. Również dla OP ten film wideo (zrobiłem) na wzorcach modułów w TypeScript może ci się przydać: https://www.youtube.com/watch?v=KDrWLMUY0R0&hd=1 – basarat

Odpowiedz

4

Można po prostu owinąć klasę wewnątrz module

Moduł sam będzie globalna, ale jeśli nie eksportować klasę, nie ma się martwić o zanieczyszczanie zasięg globalny z jedną nazwą modułu.

Więc ten maszynopis:

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

przyniesie następujące JS:

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

Cześć, dziękuję za odpowiedź. Byłem w trakcie edycji mojego pytania, aby rozwinąć moją linię, że "Jeśli umieściłem klasę w module TypeScript, to js generuje z nazwą modułu jako zmienną globalną:" - edycja była wygenerowanym kodem, który jest ładny bardzo podobny do twojego. Chodzi o to, że (w twoim przykładzie) var MyModule jest teraz globalny. Wymieniliśmy kontroler globalnie dla modułu globalnego. Jeśli inna biblioteka javascript ma globalną zmienną MyModule, to pojawia się chaos! – user603563

+1

@ user603563 - Niezupełnie dlatego, że używa wzoru modułu odkrywczego. Nie będzie więc ponownie definiował modułu, jeśli już istnieje. Chaos pojawi się tylko wtedy, gdy dodasz coś do tego modułu, którego spodziewasz się uzyskać na zewnątrz. W tym przypadku nie dodajesz klasy do modułu, więc nigdy nie będzie konfliktu. To tylko przejście. – Josh

+1

Właśnie wróciłem do moich referencji JS i tak ponownie nauczyłem się, że zamiast nukania wcześniej zadeklarowanego MyObject, kolejne zmiany MyObject'a po prostu dodadzą do istniejącego obiektu (lub nie zmienią się, jeśli, jak to jest w tym przypadku, nic Robi się do MyObject) Ok, no cóż (chociaż jestem nienawistny, ponieważ nie odpowiada, czy TypeScript może całkowicie uniknąć zanieczyszczania zasięgu globalnego) Zaznaczę to jako odpowiedź, ponieważ dzięki tym komentarzom to odpowiednio tłumaczy, dlaczego to robi. 'T liczy się tak bardzo, jak myślałem ... – user603563

2

Quick Update

W najnowszych wersjach maszynopis ty może gniazdo klasa wewnątrz Iife:

(() => { 
    class Example { 

    } 
})(); 

Wynikiem jest:

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

Original Odpowiedź

Możesz uniknąć dodawania do t ma zasięg globalny z wykorzystaniem wzorca modułu, takiego jak AMD lub CommonJS. Kiedy używasz któregokolwiek z nich, każdy plik TypeScript jest uważany za moduł zewnętrzny i nie ma go w zasięgu globalnym.

Ten przykład usuwa Angular dla celów przykładu, ale podczas gdy RequireJS dodaje metodę define do globalnej, żaden z twoich kodów nie jest umieszczony w tym zakresie.

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> 

wygląda Co app.js jak:

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

Alternatywnie ... jak wiesz ... nadal możesz zaimplementować wszystko za pomocą JavaScriptu, którego używasz, jeśli chcesz - nadal będziesz otrzymywać autouzupełnianie i sprawdzanie typu, które są głównymi korzyściami, nawet jeśli nie jesteś t uzyskiwanie klas.

+0

Dzięki za odpowiedź. Nie jestem zaznajomiony z AMD (RequireJS) lub CommonJS. Dodanie do tego dodatkowej biblioteki stanowiło złożoność, której miałem nadzieję uniknąć (mając nadzieję na rozwiązanie TS) ... ale będę badał. – user603563

+0

Zależy od tego, jak bardzo chcesz pozostać poza zasięgiem globalnym. Możesz użyć pojedynczego modułu i rozszerzyć go z każdym modułem, który byłby "tylko jedną rzeczą o zasięgu globalnym", która może być dla ciebie akceptowalna. Ta odpowiedź to odpowiedź "brak kodu w zasięgu globalnym". – Fenton

1

Josh jest prawidłowe. Użyj modułu. Poza tym dobrym pomysłem jest użycie pomulacza, który ma opcję owinięcia całej aplikacji w zamknięcie w czasie kompilacji.

To nie jest odpowiedź na twoje pytanie, ale raczej sugestia.

Na marginesie, należy rozważyć tę składnię dla kontrolerów

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); 

} 

Wraz z tym składni byłoby użyć składni controllerAs.

0

Tak jak w JavaScript, można całkowicie uniknąć zanieczyszczenia przestrzeni nazw poprzez zawijanie deklaracji wewnątrz natychmiastowego wywołania funkcji.

Więc oryginalny JavaScript:

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

staje następujące maszynopis:

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

    angular.module('myModule', []) 
    .controller('MyController', MyController); 
})(); 

Zauważ, że wprowadza to żadnych nazwisk do otaczającego zakresie. Właściwie oryginalny JavaScript jest całkowicie poprawny TypeScript, ale nie korzysta z TypeScript. Zwróć też uwagę, że nieco zmodyfikowałem styl.

W każdym razie, jeśli nie korzystasz z modułów z modułem ładującym moduły, takich jak RequireJS, SystemJS lub co ty, nadal możesz uniknąć zanieczyszczenia przestrzeni nazw, postępując zgodnie z wypróbowanym i prawdziwym wzorcem IIFE. To jest moja rekomendacja.