Analogia Candy Cup
Wersja 1: Kubek na każdy cukierek
Powiedzmy, że napisałeś taki kod:
Mod1.ts
export namespace A {
export class Twix { ... }
}
Mod2.ts
export namespace A {
export class PeanutButterCup { ... }
}
Mod3.ts
export namespace A {
export class KitKat { ... }
}
Utworzyłeś tę konfigurację:
Każdy moduł (arkusz papieru) otrzymuje własną filiżankę o nazwie A
. Jest to bezużyteczne - tak naprawdę nie organizujesz tutaj swojego cukierka, po prostu dodajesz dodatkowy krok (wyjmując go z kubka) między tobą a smakołykami.
Wersja 2: Jeden kubek w zasięgu globalnym
Jeśli nie korzystasz z modułów, możesz napisać taki kod (zwróć uwagę na brak export
deklaracji):
global1.ts
namespace A {
export class Twix { ... }
}
global2.ts
namespace A {
export class PeanutButterCup { ... }
}
global3.ts
namespace A {
export class KitKat { ... }
}
Ten kod tworzy scaloną przestrzeń nazw A
w zasięgu globalnym:
Ta konfiguracja jest przydatna, ale nie ma zastosowania w przypadku modułów (ponieważ moduły nie zanieczyszczają zasięgu globalnego).
Wersja 3: Going cupless
Wracając do pierwotnego przykład kubki A
, A
i A
nie robią ci żadnych przysług. Zamiast tego możesz napisać kod jako:
Mod1.ts
export class Twix { ... }
Mod2.ts
export class PeanutButterCup { ... }
Mod3.ts
export class KitKat { ... }
aby utworzyć zdjęcie, które wygląda następująco:
Dużo lepiej!
Jeśli nadal zastanawiasz się, jak bardzo chcesz używać przestrzeni nazw w swoich modułach, czytaj dalej ...
To nie są koncepcje, których szukasz
Musimy przede wszystkim wrócić do początków istnienia obszarów nazw i zbadać, czy te przyczyny mają sens w przypadku modułów zewnętrznych.
Organizacja : Przestrzenie nazw są przydatne do grupowania logicznie powiązanych obiektów i typów. Na przykład w języku C # znajdziesz wszystkie typy kolekcji System.Collections
. Organizując nasze typy w hierarchiczne przestrzenie nazw, zapewniamy dobre wrażenia „odkrywcze” użytkownikom tych typów.
Konflikty nazw: Przestrzenie nazw są ważne, aby uniknąć kolizji nazw. Na przykład możesz mieć My.Application.Customer.AddForm
i My.Application.Order.AddForm
- dwa typy o tej samej nazwie, ale o innej przestrzeni nazw. W języku, w którym wszystkie identyfikatory istnieją w tym samym zakresie głównym, a wszystkie zestawy ładują wszystkie typy, bardzo ważne jest, aby wszystko było w przestrzeni nazw.
Czy te powody mają sens w modułach zewnętrznych?
Organizacja : Moduły zewnętrzne są już koniecznie obecne w systemie plików. Musimy je rozwiązać według ścieżki i nazwy pliku, więc mamy do dyspozycji logiczny schemat organizacyjny. Możemy mieć /collections/generic/
folder z list
modułem.
Konflikty nazw : To nie dotyczy w ogóle modułów zewnętrznych. W module nie ma żadnego uzasadnionego powodu, aby mieć dwa obiekty o tej samej nazwie. Od strony konsumpcji konsument dowolnego modułu może wybrać nazwę, której będzie używał w odniesieniu do modułu, więc przypadkowe konflikty nazw są niemożliwe.
Nawet jeśli nie wierzysz, że przyczyny te są odpowiednio rozwiązane przez sposób działania modułów, „rozwiązanie” próby użycia przestrzeni nazw w modułach zewnętrznych nawet nie działa.
Pudełka w Pudełka w Pudełkach
Historia:
Twój przyjaciel Bob dzwoni do ciebie. „Mam świetny nowy program organizacyjny w moim domu”, mówi, „chodź, sprawdź to!”. Schludnie, zobaczmy, co wymyślił Bob.
Zaczynasz w kuchni i otwierasz spiżarnię. Istnieje 60 różnych pudełek, każde oznaczone jako „Spiżarnia”. Losowo wybierasz pudełko i je otwierasz. Wewnątrz znajduje się pojedyncze pudełko z napisem „Ziarna”. Otworzysz okno „Ziarna” i znajdziesz pojedyncze pudełko z etykietą „Makaron”. Otworzysz pudełko „Makaron” i znajdziesz pojedyncze pudełko z napisem „Penne”. Otworzysz to pudełko i znajdziesz, jak się spodziewasz, torebkę makaronu penne.
Nieco zdezorientowany podnosisz sąsiednie pudełko, oznaczone również jako „Spiżarnia”. Wewnątrz znajduje się pojedyncze pudełko, ponownie oznaczone jako „Ziarna”. Otworzysz okno „Ziarna” i ponownie znajdziesz pojedyncze pudełko z etykietą „Makaron”. Otworzysz pudełko „Makaron” i znajdziesz jedno pudełko, które ma etykietę „Rigatoni”. Otwierasz to pudełko i znajdujesz ... torebkę makaronu rigatoni.
"Wspaniale!" mówi Bob. „Wszystko jest w przestrzeni nazw!”.
„Ale Bob ...” odpowiadasz. „Twój schemat organizacyjny jest bezużyteczny. Musisz otworzyć kilka pudełek, aby dostać się do czegokolwiek, a znalezienie czegoś nie jest wygodniejsze, niż gdybyś po prostu umieścił wszystko w jednym pudełku zamiast trzech . W rzeczywistości, ponieważ spiżarnia jest już posortowana półka po półce, w ogóle nie potrzebujesz pudełek. Dlaczego nie po prostu położyć makaronu na półce i podnieść go, gdy jest potrzebny? ”
„Nie rozumiesz - muszę się upewnić, że nikt inny nie umieści czegoś, co nie należy do przestrzeni nazw„ Spiżarnia ”. I bezpiecznie zorganizowałem cały mój makaron w Pantry.Grains.Pasta
przestrzeni nazw, aby łatwo go znaleźć”
Bob jest bardzo zdezorientowanym mężczyzną.
Moduły są ich własnym pudełkiem
Prawdopodobnie zdarzyło Ci się coś podobnego w prawdziwym życiu: zamawiasz kilka rzeczy na Amazon, a każdy przedmiot pojawia się we własnym pudełku, z mniejszym pudełkiem w środku, z przedmiotem zapakowanym we własne opakowanie. Nawet jeśli pudełka wewnętrzne są podobne, przesyłki nie są użytecznie „łączone”.
Idąc za analogią skrzynki, kluczową obserwacją jest to, że moduły zewnętrzne są ich własną skrzynką . Może to być bardzo złożony przedmiot z dużą ilością funkcji, ale każdy dany moduł zewnętrzny jest własnym pudełkiem.
Wskazówki dotyczące modułów zewnętrznych
Teraz, gdy zorientowaliśmy się, że nie musimy używać „przestrzeni nazw”, w jaki sposób powinniśmy organizować nasze moduły? Poniżej przedstawiono niektóre zasady przewodnie i przykłady.
Eksportuj tak blisko najwyższego poziomu, jak to możliwe
- Jeśli eksportujesz tylko jedną klasę lub funkcję, użyj
export default
:
MyClass.ts
export default class SomeType {
constructor() { ... }
}
MyFunc.ts
function getThing() { return 'thing'; }
export default getThing;
Konsumpcja
import t from './MyClass';
import f from './MyFunc';
var x = new t();
console.log(f());
Jest to optymalne dla konsumentów. Mogą nazwać twój typ, jak chcą ( t
w tym przypadku) i nie muszą wykonywać żadnych dodatkowych kropek, aby znaleźć twoje obiekty.
- Jeśli eksportujesz wiele obiektów, umieść je wszystkie na najwyższym poziomie:
MyThings.ts
export class SomeType { ... }
export function someFunc() { ... }
Konsumpcja
import * as m from './MyThings';
var x = new m.SomeType();
var y = m.someFunc();
- Jeśli eksportujesz dużą liczbę rzeczy, tylko wtedy powinieneś użyć słowa kluczowego
module
/ namespace
:
MyLargeModule.ts
export namespace Animals {
export class Dog { ... }
export class Cat { ... }
}
export namespace Plants {
export class Tree { ... }
}
Konsumpcja
import { Animals, Plants} from './MyLargeModule';
var x = new Animals.Dog();
Czerwone flagi
Wszystkie poniższe są czerwonymi flagami dla struktury modułu. Sprawdź dokładnie, czy nie próbujesz przestrzeni nazw zewnętrznych modułów, jeśli któryś z nich dotyczy twoich plików:
- Plik, którego jedyną deklaracją najwyższego poziomu jest
export module Foo { ... }
(usuń Foo
i przenieś wszystko „w górę” o poziom)
- Plik, który ma jeden
export class
lub export function
który nie jestexport default
- Wiele plików, które mają to samo
export module Foo {
na najwyższym poziomie (nie myśl, że zostaną połączone w jeden Foo
!)