Development Tip

모듈 대 네임 스페이스-가져 오기 및 Typescript 필요

yourdevel 2020. 10. 19. 12:52
반응형

모듈 대 네임 스페이스-가져 오기 및 Typescript 필요


나는 많은 혼란 module/namespace/exportimport, 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;
    }

})();

Using IIFE you can make eliminate introducing MyApp as a global variable in the first example.

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

There are two things:

  • A module in TypeScript is a standard ES6 notion, it uses import / export keywords at the top level of the code;
  • A namespace is a notion specific to TypeScript to help to organize the code in an obsolete fashion.

Namespaces

It is almost an obsolete notion. Prior to ES6 modules, the common way to separate JavaScript code in a browser was to create global variables. For example, all the functions of an API like underscore was located in a global variable named _.

This old way to proceed is like Java packages or PHP namespaces. It is not adapted to the Web. The new ECMAScript standard solves issues like: how to use two libraries that have the same name? How to use two distinct versions of the same library?

Notice: In versions of TypeScript prior to the ECMAScript definition of “modules” (summer 2014), namespaces were called “internal modules” and modules were called “external modules”.

Notice 2: The keyword export inside a namespace is a non-standard TypeScript usage of the keyword. It is the means to declare a thing that is publicly accessible from outside the namespace.

ES6 modules

A module is a file that contains keywords import or export at the top level of the code.

TypeScript follows the standard from ECMAScript. I suggest to read a good introduction to ES6 modules in an article from Mozilla.

If you want to use modules in a front-end application (in a browser), then you will have to use a bundler (Webpack [the documentation here], Browserify) or a loader (SystemJS [a tutorial here], RequireJS) and to configure TypeScript with this environment.

If your code is executed in Node.js, just configure the TypeScript compiler to generate the CommonJS format.

Notice: A namespace can be declared in a module. In that case, it won't be accessible as a global variable from outside the module. However, it can be exported from the module.


  1. module is for external packages 2. namespace is for internal packages

Actually the module keyword has been replaced with the namespace keyword.

A better statement is thus Modules are what used to be called external modules, namespace is what used to be called internal modules.

More

Hope this helps futher : https://basarat.gitbooks.io/typescript/content/docs/project/modules.html


"require" and "import" are equivalent in functionality. we can use them both interchangeably because we have transpilers that don't really care whether the browser supports them natively or not. but, while "require" has its roots in old coding style coming from CommonJS back to 2009, "import" is deriving its syntax from the widely accepted ES6 (ES2015) syntax. so you should use "import" for new projects and not "require".

참고URL : https://stackoverflow.com/questions/38582352/module-vs-namespace-import-vs-require-typescript

반응형