IT story

TypeScript 외부 모듈과 함께 네임 스페이스를 사용하려면 어떻게합니까?

hot-time 2020. 4. 28. 08:26
반응형

TypeScript 외부 모듈과 함께 네임 스페이스를 사용하려면 어떻게합니까?


코드가 있습니다.

baseTypes.ts

export namespace Living.Things {
  export class Animal {
    move() { /* ... */ }
  }
  export class Plant {
    photosynthesize() { /* ... */ }
  }
}

dog.ts

import b = require('./baseTypes');

export namespace Living.Things {
  // Error, can't find name 'Animal', ??
  export class Dog extends Animal {
    woof() { }
  }
}

tree.ts

// Error, can't use the same name twice, ??
import b = require('./baseTypes');
import b = require('./dogs');

namespace Living.Things {
  // Why do I have to write b.Living.Things.Plant instead of b.Plant??
  class Tree extends b.Living.Things.Plant {

  }
}

이것은 모두 매우 혼란 스럽다. 외부 모듈을 모두 사용하여 유형을 동일한 네임 스페이스에 기여하고 싶습니다 Living.Things. 이 기능이 전혀 작동하지 않는 것 같습니다 . Animal에서 볼 수 없습니다 dogs.ts. 나는 전체 네임 스페이스 이름을 쓸 필요가 b.Living.Things.Plant의를 tree.ts. 파일에서 동일한 네임 스페이스의 여러 개체를 결합하는 것은 작동하지 않습니다. 어떻게해야합니까?


캔디 컵 비유

버전 1 : 모든 사탕을위한 컵

다음과 같은 코드를 작성했다고 가정 해 봅시다.

Mod1.ts

export namespace A {
    export class Twix { ... }
}

Mod2.ts

export namespace A {
    export class PeanutButterCup { ... }
}

Mod3.ts

export namespace A {
     export class KitKat { ... }
}

이 설정을 만들었습니다 : 여기에 이미지 설명을 입력하십시오

각 모듈 (용지) 에는 이름이 지정된 자체 컵A있습니다. 이것은 쓸모가 없습니다-실제로 사탕을 조직 하는 것이 아니라, 당신과 간식 사이에 추가 단계 (컵에서 꺼내기)를 추가하는 것입니다.


버전 2 : 글로벌 범위에서 한 컵

모듈을 사용하지 않았다면 다음과 같은 코드를 작성할 수 있습니다 ( export선언 부족 ).

global1.ts

namespace A {
    export class Twix { ... }
}

global2.ts

namespace A {
    export class PeanutButterCup { ... }
}

global3.ts

namespace A {
     export class KitKat { ... }
}

코드 A는 전역 범위에서 병합 된 네임 스페이스 만듭니다 .

여기에 이미지 설명을 입력하십시오

이 설정은 유용하지만 모듈의 경우에는 적용되지 않습니다 (모듈이 전역 범위를 오염시키지 않기 때문에).


버전 3 : 컵리스

원래의 예를 다시가는, 컵은 A, A그리고 A당신에게 호의를하고 있지 않습니다. 대신 코드를 다음과 같이 작성할 수 있습니다.

Mod1.ts

export class Twix { ... }

Mod2.ts

export class PeanutButterCup { ... }

Mod3.ts

export class KitKat { ... }

다음과 같은 그림을 만들려면

여기에 이미지 설명을 입력하십시오

훨씬 낫다!

이제 모듈에서 네임 스페이스를 얼마나 많이 사용하고 싶은지 아직도 생각하고 있다면 계속 읽으십시오 ...


이들은 당신이 찾고있는 개념이 아닙니다

네임 스페이스가 처음 존재하는 이유의 근원으로 돌아가서 이러한 이유가 외부 모듈에 적합한 지 여부를 조사해야합니다.

구성 : 네임 스페이스는 논리적으로 관련된 객체와 유형을 그룹화하는 데 편리합니다. 예를 들어 C #에서는에서 모든 컬렉션 유형을 찾을 수 있습니다 System.Collections. 유형을 계층 적 네임 스페이스로 구성하여 해당 유형의 사용자에게 좋은 "발견"환경을 제공합니다.

이름 충돌 : 이름 공간은 이름 충돌을 피하기 위해 중요합니다. 예를 들어, 당신은 할 수 My.Application.Customer.AddFormMy.Application.Order.AddForm두 개의 동일한 이름을 가진 유형,하지만 다른 네임 스페이스를 -. 모든 식별자가 동일한 루트 범위에 있고 모든 어셈블리가 모든 유형을로드하는 언어에서는 모든 것이 네임 스페이스에 있어야합니다.

이러한 이유는 외부 모듈에서 의미가 있습니까?

구성 : 외부 모듈은 이미 파일 시스템에 존재합니다. 경로와 파일 이름으로 해결해야하므로 사용할 수있는 논리적 구성 체계가 있습니다. 모듈 이있는 /collections/generic/폴더를 가질 수 있습니다 list.

이름 충돌 : 이것은 외부 모듈에 전혀 적용되지 않습니다. 모듈 에서 동일한 이름을 가진 두 개의 객체를 가질만한 이유는 없습니다. 소비 측면에서 특정 모듈 소비자 는 모듈을 참조하는 데 사용할 이름을 선택하므로 우연한 이름 충돌이 불가능합니다.


모듈이 작동하는 방식으로 이러한 이유가 적절히 해결되었다고 생각하지 않더라도 외부 모듈에서 네임 스페이스를 사용하려는 "솔루션"은 작동하지 않습니다.

상자에 상자에 상자

이야기:

친구 Bob이 전화합니다. "저는 집에 아주 새로운 조직 체계가 있습니다." 깔끔한, 밥이 무슨 일을했는지 ​​보자.

부엌에서 시작하여 식료품 저장실을여십시오. 각각 "Pantry"라고 표시된 60 개의 서로 다른 상자가 있습니다. 상자를 무작위로 골라서 엽니 다. 내부에는 "곡물"이라는 단일 상자가 있습니다. "곡물"상자를 열고 "파스타"라고 표시된 단일 상자를 찾으십시오. "파스타"상자를 열고 "펜"이라는 단일 상자를 찾으십시오. 이 상자를 열고 예상대로 펜네 파스타 한 봉지를 찾으십시오.

약간 혼동되면 "Pantry"라고 표시된 인접 상자를 선택하십시오. 내부에는 "곡물"이라는 레이블이 붙은 단일 상자가 있습니다. "곡물"상자를 열고 "파스타"라고 표시된 단일 상자를 다시 찾으십시오. "파스타"상자를 열고 하나의 상자를 찾으십시오.이 상자에는 "Rigatoni"라는 레이블이 붙어 있습니다. 이 상자를 열고 리가 토니 파스타 한 봉지를 찾으세요

"좋아요!" 밥이 말합니다. "모든 것이 네임 스페이스에 있습니다!".

"하지만 밥 .." "당신의 조직 방식은 당신은 아무것도에 도착하는 상자의 무리를 열어야합니다. 쓸모이며, 당신은 단지 모든 것을 넣어했던 것보다 아무것도 찾을 실제로 더 편리 아니라 하나 개 대신 상자 .에서는 사실, 이후 식품 저장실은 이미 선반별로 분류되어 있으므로 상자가 전혀 필요하지 않습니다. 선반에 파스타를 놓고 필요할 때 집어 올리는 것이 어떻습니까? "

"당신은 이해하지 못합니다-다른 누구도 'Pantry'네임 스페이스에 속하지 않은 것을 넣지 않도록해야합니다. 그리고 모든 파스타를 Pantry.Grains.Pasta네임 스페이스에 안전하게 정리하여 쉽게 찾을 수 있습니다."

밥은 매우 혼란스러운 사람입니다.

모듈은 자체 상자입니다

아마도 실제 상황에서 비슷한 일이 있었을 것입니다. 아마존에서 몇 가지 물건을 주문하면 각 상자에 작은 상자가 들어 있고 상자에 포장되어있는 각 상자에 자체 항목이 표시됩니다. 내부 상자가 유사하더라도 발송물은 유용하게 "결합"되지 않습니다.

박스 유추와 마찬가지로 주요 관찰 사항은 외부 모듈이 자체 박스라는 것 입니다. 많은 기능을 가진 매우 복잡한 항목 일 수 있지만 지정된 외부 모듈은 자체 상자입니다.


외부 모듈에 대한 지침

이제 '네임 스페이스'를 사용할 필요가 없다는 것을 알았으므로 모듈을 어떻게 구성해야합니까? 몇 가지 지침 원칙과 예는 다음과 같습니다.

가능한 한 최상위 수준에 가깝게 내보내기

  • 단일 클래스 또는 함수 만 내보내는 경우 다음을 사용하십시오 export default.

MyClass.ts

export default class SomeType {
  constructor() { ... }
}

MyFunc.ts

function getThing() { return 'thing'; }
export default getThing;

소비

import t from './MyClass';
import f from './MyFunc';
var x = new t();
console.log(f());

이것은 소비자에게 최적입니다. 그들은 원하는대로 ( t이 경우) 당신의 유형의 이름을 지정할 수 있으며 물체를 찾기 위해 불필요한 도팅을 할 필요가 없습니다.

  • 여러 객체를 내보내는 경우 모두 최상위 레벨에 두십시오.

MyThings.ts

export class SomeType { ... }
export function someFunc() { ... }

소비

import * as m from './MyThings';
var x = new m.SomeType();
var y = m.someFunc();
  • 많은 것을 내보내는 경우에만 module/ namespace키워드 를 사용해야합니다 .

MyLargeModule.ts

export namespace Animals {
  export class Dog { ... }
  export class Cat { ... }
}
export namespace Plants {
  export class Tree { ... }
}

소비

import { Animals, Plants} from './MyLargeModule';
var x = new Animals.Dog();

붉은 깃발

다음은 모두 모듈 구조화를위한 위험 신호입니다. 다음 중 하나라도 파일에 적용되는 경우 외부 모듈의 네임 스페이스를 만들려고하지 않는지 다시 확인하십시오.

  • 최상위 선언 만있는 파일 export module Foo { ... }( Foo모든 것을 제거 하고 레벨 위로 이동)
  • 단일 파일이 export class있거나 export function그렇지 않은 파일export default
  • export module Foo {최상위 수준에서 동일한 여러 파일 (이 파일들이 하나로 결합 될 것이라고 생각하지 마십시오 Foo!)

아무것도 라이언의 대답은 잘못하지만 유지 관리하는 방법을 찾고 여기 온 사람들을위한 하나의 클래스 당 파일 여전히 제대로을 참조하시기 바랍니다 ES6 네임 스페이스를 사용하는 동안 구조를 Microsoft에서 유용 자원.

해당 문서를 읽은 후 나에게 불분명 한 가지입니다 : 전체를 가져 오는 방법으로 모듈 (합병) 하나 import .

이 답변을 업데이트하려면 순환을 다시 편집하십시오 . 네임 스페이스에 대한 몇 가지 접근 방식이 TS에 등장합니다.

하나의 파일에있는 모든 모듈 클래스.

export namespace Shapes {
    export class Triangle {}
    export class Square {}      
}

네임 스페이스로 파일 가져 오기 및 재 할당

import { Triangle as _Triangle } from './triangle';
import { Square as _Square } from './square';

export namespace Shapes {
  export const Triangle = _Triangle;
  export const Square = _Square;
}

배럴

// ./shapes/index.ts
export { Triangle } from './triangle';
export { Square } from './square';

// in importing file:
import * as Shapes from './shapes/index.ts';
// by node module convention, you can ignore '/index.ts':
import * as Shapes from './shapes';
let myTriangle = new Shapes.Triangle();

마지막 고려 사항. 당신은 수있는 각 파일을 네임 스페이스

// triangle.ts
export namespace Shapes {
    export class Triangle {}
}

// square.ts
export namespace Shapes {
    export class Square {}
}

그러나 동일한 네임 스페이스에서 두 개의 클래스를 가져 오면 TS는 중복 식별자가 있다고 불평합니다. 이때 유일한 해결책은 네임 스페이스의 별칭을 지정하는 것입니다.

import { Shapes } from './square';
import { Shapes as _Shapes } from './triangle';

// ugh
let myTriangle = new _Shapes.Shapes.Triangle();

이 앨리어싱은 절대적으로 끔찍하므로 절대하지 마십시오. 위의 접근 방식을 사용하는 것이 좋습니다. 개인적으로 나는 '배럴'을 선호합니다.


폴더별로 정리해보십시오.

baseTypes.ts

export class Animal {
    move() { /* ... */ }
}

export class Plant {
    photosynthesize() { /* ... */ }
}

dog.ts

import b = require('./baseTypes');

export class Dog extends b.Animal {
    woof() { }
}   

tree.ts

import b = require('./baseTypes');

class Tree extends b.Plant {
}

LivingThings.ts

import dog = require('./dog')
import tree = require('./tree')

export = {
    dog: dog,
    tree: tree
}

main.ts

import LivingThings = require('./LivingThings');
console.log(LivingThings.Tree)
console.log(LivingThings.Dog)

아이디어는 모듈 자체가 네임 스페이스에 참여하고 있거나 신경 쓰지 않아야한다는 것입니다. 그러나 이것은 프로젝트에 사용중인 모듈 시스템 유형에 관계없이 작고 합리적인 방식으로 API를 소비자에게 노출시킵니다.


Albinofrenchy 답변의 작은 시행 :

base.ts

export class Animal {
move() { /* ... */ }
}

export class Plant {
  photosynthesize() { /* ... */ }
}

dog.ts

import * as b from './base';

export class Dog extends b.Animal {
   woof() { }
} 

things.ts

import { Dog } from './dog'

namespace things {
  export const dog = Dog;
}

export = things;

main.ts

import * as things from './things';

console.log(things.dog);

OP 나는 당신과 함께 있습니다. 다시 한 번, 300 개 이상의 투표로 그 대답에는 아무런 문제가 없지만 내 의견은 다음과 같습니다.

  1. 클래스를 아늑한 따뜻한 파일에 개별적으로 넣는 것은 어떤 문제입니까? 이것이 더 잘 보이게 할 것입니까? (또는 모든 모델에서 1000 줄 파일을 좋아하는 사람)

  2. 따라서 첫 번째 파일을 가져 오려면 import import import ... man, srsly, model 파일, .d.ts 파일과 같은 각 모델 파일에서 import를 가져와야합니다. 거기에? 간단하고 깔끔해야합니다. 수입품이 필요한 이유는 무엇입니까? 왜? C #에서 네임 스페이스를 얻었습니다.

  3. 그리고 그때까지 문자 그대로 "filenames.ts"를 식별자로 사용합니다. 식별자로서 ... 2017 년에 와서 아직도 그렇게합니까? 이마는 화성으로 돌아가서 1000 년 더 잠을 잔다.

슬프게도 내 대답은 : nop, 모든 가져 오기를 사용하지 않거나 해당 파일 이름을 식별자로 사용하는 경우 "네임 스페이스"를 기능적으로 만들 수 없습니다 (실제로 바보라고 생각합니다). 다른 옵션은 다음과 같습니다. 이러한 모든 종속성을 filenameasidentifier.ts라는 상자에 넣고 사용하십시오.

export namespace(or module) boxInBox {} .

단순히 클래스 위에있는 참조를 얻으려고 할 때 같은 이름으로 다른 클래스에 액세스하려고하지 않도록 랩핑하십시오.


이 주제와 관련하여 본 몇 가지 질문 / 의견은 마치 사람이 Namespace'모듈 별칭'을 의미 하는 곳에서 사용 하는 것처럼 들립니다 . Ryan Cavanaugh가 자신의 의견 중 하나에서 언급했듯이 '래퍼'모듈로 여러 모듈을 다시 내보낼 수 있습니다.

동일한 모듈 이름 / 별칭에서 모두 가져 오려면 래퍼 모듈을의 경로 매핑과 결합하십시오 tsconfig.json.

예:

./path/to/CompanyName.Products/Foo.ts

export class Foo {
    ...
}


./path/to/CompanyName.Products/Bar.ts

export class Bar {
    ...
}


./path/to/CompanyName.Products/index.ts

export { Foo } from './Foo';
export { Bar } from './Bar';



tsconfig.json

{
    "compilerOptions": {
        ...
        paths: {
            ...
            "CompanyName.Products": ["./path/to/CompanyName.Products/index"],
            ...
        }
        ...
    }
    ...
}



main.ts

import { Foo, Bar } from 'CompanyName.Products'

참고 : 출력 .js 파일의 모듈 해상도는 https://github.com/tleunen/babel-plugin-module-resolver 와 같이 어떻게 든 처리해야합니다.

.babelrc별명 분석을 처리하는 :

{
    "plugins": [
        [ "module-resolver", {
            "cwd": "babelrc",
            "alias": {
                "CompanyName.Products": "./path/to/typescript/build/output/CompanyName.Products/index.js"
            }
        }],
        ... other plugins ...
    ]
}

dog.ts

import b = require('./baseTypes');

export module Living.Things {
    // Error, can't find name 'Animal', ??
    // Solved: can find, if properly referenced; exporting modules is useless, anyhow
    export class Dog extends b.Living.Things.Animal {
        public woof(): void {
            return;
        }
    }
}

tree.ts

// Error, can't use the same name twice, ??
// Solved: cannot declare let or const variable twice in same scope either: just use a different name
import b = require('./baseTypes');
import d = require('./dog');

module Living.Things {
    // Why do I have to write b.Living.Things.Plant instead of b.Plant??
    class Tree extends b.Living.Things.Plant {
    }
}

이 네임 스페이스 모듈을 사용해보십시오

namespaceModuleFile.ts

export namespace Bookname{
export class Snows{
    name:any;
    constructor(bookname){
        console.log(bookname);
    }
}
export class Adventure{
    name:any;
    constructor(bookname){
        console.log(bookname);
    }
}
}





export namespace TreeList{
export class MangoTree{
    name:any;
    constructor(treeName){
        console.log(treeName);
    }
}
export class GuvavaTree{
    name:any;
    constructor(treeName){
        console.log(treeName);
    }
}
}

bookTreeCombine.ts

--- 컴파일 부분 ---

import {Bookname , TreeList} from './namespaceModule';
import b = require('./namespaceModule');
let BooknameLists = new Bookname.Adventure('Pirate treasure');
BooknameLists = new Bookname.Snows('ways to write a book'); 
const TreeLis = new TreeList.MangoTree('trees present in nature');
const TreeLists = new TreeList.GuvavaTree('trees are the celebraties');

코드를 구성하는 올바른 방법은 네임 스페이스 대신 별도의 디렉토리를 사용하는 것입니다. 각 클래스는 자체 파일, 해당 네임 스페이스 폴더에 있습니다. index.ts는 각 파일 만 다시 내 보냅니다. 실제 코드는 index.ts 파일에 없어야합니다. 이와 같이 코드를 구성하면 훨씬 쉽게 탐색 할 수 있으며 디렉토리 구조에 따라 자체 문서화됩니다.

// index.ts
import * as greeter from './greeter';
import * as somethingElse from './somethingElse';

export {greeter, somethingElse};

// greeter/index.ts
export * from './greetings.js';
...

// greeter/greetings.ts
export const helloWorld = "Hello World";

그런 다음 다음과 같이 사용하십시오.

import { greeter } from 'your-package'; //Import it like normal, be it from an NPM module or from a directory.
// You can also use the following syntax, if you prefer:
import * as package from 'your-package';

console.log(greeter.helloWorld);

참고 URL : https://stackoverflow.com/questions/30357634/how-do-i-use-namespaces-with-typescript-external-modules

반응형