나는 많은 혼란 module/namespace/export
과 import, require, reference
사용법을 얻고 있습니다. Java 배경에서 누군가가 언제 무엇을 사용해야하며 올바른 디자인이 무엇인지 간단히 설명해 줄 수 있습니까? 샘플 프로젝트를 작성할 때 엉망이 된 느낌
지금까지 이것은 내 이해입니다. 1. module
외부 패키지 용입니다. 2. namespace
내부 패키지 용입니다.
- 분류 방법을 이해하지 못했습니까?
- 클래스, 네임 스페이스 또는 패키지를 언제 내 보내야합니까?
- 패키지 / 네임 스페이스를 내 보내면 그 안의 모든 클래스를 내보내거나 명시 적으로 내 보내야합니다.
- 각각을 어떻게 가져 오거나 요구할 수 있습니까?
doc에 따르면 각 관리자 / 모델에 대해 각 “ts”파일을 만드는 경우 Typescript는 “네임 스페이스”사용을 권장하지 않습니까? 참조 경로를 직접 사용 하시겠습니까?
ES6 / ES5 등에 대해 잘 모르고 다른 배경에서 왔으니 자세히 설명 해주세요.
나는 여러 사람이 같은 질문을 제기하거나 혼동하는 것을 보았습니다. 누군가가 실제 시나리오로 자세히 설명 할 수 있기를 바랍니다.
답변
분류 방법을 이해하지 못했습니까?
네임 스페이스는 코드를 구성 / 캡슐화하는 데 사용됩니다. 외부 모듈은 코드를 구성 / 캡슐화하고 런타임에 코드를 찾는 데 사용됩니다. 실제로 런타임에 두 가지 선택 사항이 있습니다. 1) 트랜스 파일 된 모든 코드를 하나의 파일로 결합하거나 2) 외부 모듈을 사용하고 여러 파일을 갖고 해당 파일을 가져 오기 위해 다른 메커니즘이 필요합니다.
클래스, 네임 스페이스 또는 패키지를 언제 내 보내야합니까?
유형 또는 값이있는 파일 외부에 표시되도록하려면 네임 스페이스 내부에있는 경우 내 보내야합니다. 최상위 수준에서 내보내 든 네임 스페이스 내에서 내보낼 지 여부에 따라 현재 외부 모듈에 있는지 여부가 결정됩니다.
패키지 / 네임 스페이스를 내 보내면 그 안의 모든 클래스를 내보내거나 명시 적으로 내 보내야합니다.
네임 스페이스의 클래스는 클래스가 정의 된 파일 외부에서 컴파일 타임에 볼 수 있도록 항상 명시 적으로 내 보내야합니다.
각각을 어떻게 가져 오거나 요구할 수 있습니까?
이것은 외부 모듈을 사용하고 있는지에 따라 다릅니다. 외부 모듈을 “사용”하려면 항상 가져와야합니다. 외부 모듈에없는 네임 스페이스를 가져 오는 것은 실제로 네임 스페이스에 대한 별칭을 제공하는 것입니다. 유형 / 무엇이든 별칭을 접두사로 지정해야합니다 (이것이 일반적으로 외부 모듈에 네임 스페이스를 사용하지 않는 이유입니다. 이렇게하면 외부 모듈에서 제공하는 모든 것을 참조 할 때 항상 접두사를 사용해야합니다.) 외부 모듈에없는 네임 스페이스는 파일에 걸쳐있을 수 있으므로 동일한 네임 스페이스에있는 경우 어떤 종류의 가져 오기도 필요하지 않습니다.
위의 내용을 제대로 이해하려면 배경 지식이 필요합니다. 참조 / 네임 스페이스 / 외부 모듈로 이해해야 할 핵심 사항은 이러한 구문이 컴파일 타임에 수행하는 작업과 런타임에 수행하는 작업입니다.
참조 지시문은 컴파일 타임에 형식 정보를 찾는 데 사용됩니다. 소스에는 특정 기호가 있습니다. TypeScript 컴파일러는 해당 기호에 대한 정의를 어떻게 찾습니까? 참조 지시문은 대부분 tsconfig.json 메커니즘에 포함되어 있습니다. tsconfig.json을 사용하여 모든 소스가 어디에 있는지 컴파일러에 알립니다.
네임 스페이스는 유형 정의 및 / 또는 구현을 포함 할 수 있습니다. 네임 스페이스에 유형 정보 만 포함 된 경우 런타임 매니페스트가 전혀 없습니다. JS 출력을보고 빈 JS 파일을 찾아이를 확인할 수 있습니다. 네임 스페이스에 구현 코드가있는 경우 코드는 네임 스페이스와 동일한 이름을 가진 전역 변수에 할당 된 클로저 내에서 래핑됩니다. 중첩 된 네임 스페이스를 사용하면 루트 네임 스페이스에 대한 전역 변수가 있습니다. 다시 JS 출력을 확인하십시오. 네임 스페이스는 역사적으로 JS 클라이언트 측 라이브러리가 이름 충돌 문제를 피하기 위해 시도한 방식입니다. 아이디어는 전체 라이브러리를 하나의 클로저로 래핑 한 다음 가능한 한 작은 전역 풋 프린트 (클로저를 참조하는 하나의 전역 변수)를 노출하는 것입니다. 글쎄요, 문제는 여전히 당신이 글로벌 공간에서 이름을 주장했다는 것입니다. 두 가지 버전의 라이브러리를 원하면 어떻게해야합니까? TypeScript 네임 스페이스는 네임 스페이스의 소스를 찾는 방법에 여전히 문제가 있습니다. 즉, AB를 참조하는 소스 코드는 참조 지시문을 사용하거나 tsconfig.json을 사용하여 컴파일러에게 AB를 찾는 방법을 알려주는 문제가 있습니다. 또는 네임 스페이스를 외부 모듈에 넣은 다음 외부 모듈을 가져옵니다.
외부 모듈은 서버 측 JS에서 시작되었습니다. 외부 모듈과 파일 시스템의 파일 사이에는 일대일 대응이 있습니다. 파일 시스템 디렉토리 구조를 사용하여 외부 모듈을 중첩 된 구조로 구성 할 수 있습니다. 외부 모듈을 가져 오면 일반적으로 해당 외부 모듈에 대한 런타임 종속성이 발생합니다 (외부 모듈을 가져온 다음 값 위치에서 내보내기를 사용하지 않는 경우, 즉 외부 모듈 만 가져 오는 경우는 예외입니다). 유형 정보를 얻으려면). 외부 모듈은 묵시적으로 클로저에 있으며 이것이 핵심입니다. 모듈 사용자는 원하는 지역 변수에 클로저를 할당 할 수 있습니다. TypeScript / ES6는 외부 모듈의 내보내기를 로컬 이름으로 매핑하는 것과 관련된 추가 구문을 추가하지만 이것은 단지 좋은 일입니다. 서버 측에서는 외부 모듈을 찾는 것은 비교적 간단합니다. 로컬 파일 시스템에서 외부 모듈을 나타내는 파일을 찾으십시오. 클라이언트 측에서 외부 모듈을 사용하려는 경우 브라우저에서로드 할 수있는 모듈이있는 파일 시스템에 해당하는 것이 없기 때문에 더 복잡해집니다. 따라서 이제 클라이언트 측에서는 이러한 모든 파일을 브라우저에서 원격으로 사용할 수있는 양식으로 번들링하는 방법이 필요합니다. 여기에서 Webpack과 같은 모듈 번 들러 (Webpack은 번들 모듈보다 훨씬 많은 기능을 수행합니다) 및 Browserify가 작동합니다. 모듈 번 들러는 브라우저에서 외부 모듈의 런타임 확인을 허용합니다. 브라우저에서는로드 할 수있는 모듈이있는 파일 시스템에 해당하는 것이 없기 때문에 더 복잡해집니다. 따라서 이제 클라이언트 측에서는 이러한 모든 파일을 브라우저에서 원격으로 사용할 수있는 양식으로 번들링하는 방법이 필요합니다. 여기에서 Webpack과 같은 모듈 번 들러 (Webpack은 번들 모듈보다 훨씬 많은 기능을 수행합니다) 및 Browserify가 작동합니다. 모듈 번 들러는 브라우저에서 외부 모듈의 런타임 확인을 허용합니다. 브라우저에서는로드 할 수있는 모듈이있는 파일 시스템에 해당하는 것이 없기 때문에 더 복잡해집니다. 따라서 이제 클라이언트 측에서는 이러한 모든 파일을 브라우저에서 원격으로 사용할 수있는 양식으로 번들링하는 방법이 필요합니다. 여기에서 Webpack과 같은 모듈 번 들러 (Webpack은 번들 모듈보다 훨씬 많은 기능을 수행합니다) 및 Browserify가 작동합니다. 모듈 번 들러는 브라우저에서 외부 모듈의 런타임 확인을 허용합니다.
실제 시나리오 : AngularJS. 외부 모듈이없는 척하고 단일 네임 스페이스를 사용하여 전역 공간의 오염을 제한하고 (아래 예제에서는 단일 변수 MyApp이 전역 공간에있는 전부입니다) 인터페이스 만 내보내고 AngularJS 종속성 주입을 사용하여 구현합니다. 사용할 수 있습니다. 모든 클래스를 디렉토리 루트에 넣고, tsconfig.json을 루트에 추가하고, 동일한 디렉토리 루트 아래에 angularjs 타이핑을 설치하여 tsconfig.json도 선택하도록하고, 모든 출력을 하나의 JS 파일에 결합합니다. 코드 재사용이 큰 문제가되지 않는다면 대부분의 프로젝트에서 잘 작동합니다.
MyService.ts :
namespace MyApp {
// without an export the interface is not visible outside of MyService.ts
export interface MyService {
....
}
// class is not exported; AngularJS DI will wire up the implementation
class MyServiceImpl implements MyService {
}
angular.module("MyApp").service("myService", MyServiceImpl);
}
MyController.ts :
namespace MyApp {
class MyController {
// No import of MyService is needed as we are spanning
// one namespace with multiple files.
// MyService is only used at compile time for type checking.
// AngularJS DI is done on the name of the variable.
constructor(private myService: MyService) {
}
}
angular.module("MyApp").controller("myController", MyController);
}
IIFE를 사용하여 전역 런타임 범위 오염을 방지합니다. 이 예에서는 전역 변수가 전혀 생성되지 않습니다. (tsconfig.json이 가정됩니다.)
풋 :
namespace Foo {
// without an export IFoo is not visible. No JS is generated here
// as we are only defining a type.
export interface IFoo {
x: string;
}
}
interface ITopLevel {
z: string;
}
(function(){
// export required above to make IFoo visible as we are not in the Foo namespace
class Foo1 implements Foo.IFoo {
x: string = "abc";
}
// do something with Foo1 like register it with a DI system
})();
Bar.ts :
// alias import; no external module created
import IFoo = Foo.IFoo;
(function() {
// Namespace Foo is always visible as it was defined at
// top level (outside of any other namespace).
class Bar1 implements Foo.IFoo {
x: string;
}
// equivalent to above
class Bar2 implements IFoo {
x: string;
}
// IToplevel is visible here for the same reason namespace Foo is visible
class MyToplevel implements ITopLevel {
z: string;
}
})();
IIFE를 사용하면 첫 번째 예제에서 MyApp을 전역 변수로 도입하지 않아도됩니다.
MyService.ts :
interface MyService {
....
}
(function() {
class MyServiceImpl implements MyService {
}
angular.module("MyApp").service("myService", MyServiceImpl);
})();
MyController.ts :
(function() {
class MyController {
constructor(private myService: MyService) {
}
}
angular.module("MyApp").controller("myController", MyController);
})();
답변
두 가지가 있습니다.
- TypeScript 의 모듈 은 표준 ES6 개념이며 코드 의 최상위 수준에서
import
/export
키워드 를 사용 합니다. - 네임 스페이스는 사용되지 않는 방식으로 코드를 구성하기 위해 타이프 라이터에 대한 개념 고유의 것입니다.
네임 스페이스
거의 쓸모없는 개념입니다. ES6 모듈 이전에는 브라우저에서 JavaScript 코드를 분리하는 일반적인 방법은 전역 변수를 만드는 것이 었습니다. 예를 들어 밑줄 과 같은 API의 모든 함수는 라는 전역 변수에 _
있습니다.
이 오래된 방법은 Java 패키지 또는 PHP 네임 스페이스와 같습니다. 웹에 적용되지 않습니다. 새로운 ECMAScript 표준은 다음과 같은 문제를 해결합니다. 동일한 이름을 가진 두 개의 라이브러리를 사용하는 방법? 동일한 라이브러리의 서로 다른 두 버전을 사용하는 방법은 무엇입니까?
주의 : “모듈”(2014 년 여름)의 ECMAScript 정의 이전 TypeScript 버전에서는 네임 스페이스를 “내부 모듈”이라고하고 모듈을 “외부 모듈”이라고했습니다.
주의 2 : export
a 내부 namespace
의 키워드는 키워드의 비표준 TypeScript 사용입니다. 네임 스페이스 외부에서 공개적으로 액세스 할 수있는 것을 선언하는 수단입니다.
ES6 모듈
모듈은 키워드를 포함 import
하거나 export
코드의 최상위 수준에 있는 파일입니다 .
TypeScript는 ECMAScript의 표준을 따릅니다. Mozilla의 기사에서 ES6 모듈 에 대한 좋은 소개 를 읽을 것을 제안합니다 .
프론트 엔드 애플리케이션 (브라우저에서)에서 모듈을 사용하려면 번 들러 ( Webpack [ 여기에 문서화 ], Browserify) 또는 로더 ( SystemJS [ 여기에 튜토리얼 ], RequireJS)를 사용해야합니다. 이 환경에서 TypeScript를 구성합니다.
코드가 Node.js에서 실행되는 경우 TypeScript 컴파일러를 구성하여 CommonJS 형식을 생성하십시오.
주의 : 네임 스페이스는 모듈에서 선언 될 수 있습니다. 이 경우 모듈 외부에서 전역 변수로 액세스 할 수 없습니다. 그러나 모듈에서 내보낼 수 있습니다.
답변
- 모듈은 외부 패키지 용입니다. 2. 네임 스페이스는 내부 패키지 용입니다.
실제로 module
키워드가 키워드로 대체되었습니다 namespace
.
따라서 모듈 은 외부 모듈이라고 불렸던 것이고 네임 스페이스 는 내부 모듈이라고 불렸던 것입니다.
더
이것이 더 도움이되기를 바랍니다 : https://basarat.gitbooks.io/typescript/content/docs/project/modules.html
답변
” require “및 ” import “는 기능면에서 동일합니다. 브라우저가 기본적으로 지원하는지 여부에 대해 실제로 신경 쓰지 않는 트랜스 파일러가 있기 때문에 둘 다 서로 바꿔서 사용할 수 있습니다. 그러나 ” require “는 CommonJS에서 2009 년으로 거슬러 올라가는 이전 코딩 스타일에 뿌리를두고 있지만 “import”는 널리 사용되는 ES6 (ES2015) 구문에서 구문을 파생시킵니다. 따라서 ” require “가 아닌 새 프로젝트에 ” import “를 사용해야합니다 .
답변
이름 지정 혼란
Typescript의 초기에는 네임 스페이스를 내부 모듈 이라고 하고 ES6 모듈을 외부 모듈 이라고했습니다 .
이제 네임 스페이스를 선언 들어, 타이프 라이터 팀은 사용하는 것이 좋습니다 namespace { }
대신의 module { }
외부 모듈로 명명 혼동을 피하기 위해 구문. 외부 모듈은 이제 단순히 ‘모듈’이고 내부 모듈은 ‘네임 스페이스’이기 때문입니다.
네임 스페이스
선언
Typescript의 네임 스페이스는 namespace
또는 module
키워드를 사용하여 선언 할 수 있습니다 . 두 키워드 모두 동일한 작업을 수행합니다. 그런 다음 export
키워드를 사용하여 공개 할 네임 스페이스 부분을 결정할 수 있습니다 .
// LivingThings.ts
export namespace Animals {
export class Dog { }
export class Cat { }
}
export namespace Plants {
export class Orchid { }
export class Bamboo { }
}
// LivingThingsUser.ts
import { Animals, Plants } from "./LivingThings"
논리적 그룹화
ES6 이전에는 Typescript에서 네임 스페이스를 사용하여 인터페이스, 클래스, 함수 및 변수를 캡슐화하여 관련 기능 그룹을 지원하고 구현 세부 정보를 숨겼습니다. 이렇게하면 변수가 전역 공간으로 누출되는 것을 방지 할 수 있습니다. 이는 코드 구성을 개선하고 이름 충돌을 방지하는 데 도움이되었습니다. 이제이를 달성하기 위해 ES6 모듈을 사용하는 것이 좋습니다.
네임 스페이스는 이제 앰비언트 네임 스페이스 선언에 사용됩니다.
단일 파일 사용
여러 파일에 네임 스페이스를 선언 할 수 있으며 --outFile
플래그를 사용하여 연결할 수 있습니다 . 그런 다음 <script>
HTML 페이지 의 태그 내에서 연결된 파일을 사용할 수 있습니다 . 이를 통해 모든 종속성이 포함 된 클라이언트 측 웹 애플리케이션에서 코드를 좋은 방식으로 구성 할 수 있습니다.
모듈
선언
모듈은 ES6 모듈이라고도합니다. 관련 기능을 그룹화하기 위해 여러 파일을 사용하고 export
키워드를 사용하여 원하는 객체를 공개적으로 표시합니다.
// Animals.ts
export class Dog { }
export class Cat { }
// Plants.ts
export class Orchid { }
export class Bamboo { }
// LivingThingsUser.ts
import { Dog, Cat } from "./Animals"
import { Orchid, Bamboo } from "./Plants"
논리적 그룹화
모듈의 논리적 그룹화는 관련 기능을 그룹화하기 위해 별도의 파일을 사용하여 수행됩니다. 이러한 이유로 외부 모듈을 파일 모듈 이라고도 합니다 .
단일 파일 사용
<script>
태그를 사용하여 클라이언트 측 웹 애플리케이션의 모듈을로드하지 않습니다. 너무 많은 파일을 다운로드하고 페이지를 동시에 렌더링하는 동안 브라우저가 느려질 수 있기 때문입니다. 이를 위해 CommonJS, AMD, SystemJS와 같은 모듈 로더를 사용하여 파일을 비동기 적으로로드하거나 외부 모듈 파일을 하나의 최적화 된 파일로 연결할 수 있습니다.
서버 측, 특히 Node.js의 경우 모듈을 적극 권장합니다.
그게 다야!