showmiso 2019. 10. 16. 10:05

08. 모듈
: 독립 가능한 기능의 단위

자주사용하는 공통 기능을 모듈로 정의해 사용하면, 
앱의 수정없이 모듈의 수정과 교체만으로 코드를 효과적으로 수정할 수 있습니다.

장점
1) 유지보수가 쉬워진다.
: 중복 코드 개선
2) 전역 스코프 오염 방지
: 전역 스코프는 global namespace 이므로 변수나 함수이름을 중복해서 선언할수 없습니다.
모듈 내부에 변수나 함수를 선언하면 namespace가 파일 단위로 제한되어 
global namespace를 침범하지 않습니다.
3) 재사용성 reusability
: 모듈은 프로젝트에서 자주 사용되는 공통기능으로 자주 호출될 가능성이 높습니다.
모듈화를 잘 해두면 다른 프로젝트에도 공유해 지사용하 수 있습니다. 

- modular programming
1) 모듈을 식별함
: 함수 내부의 공통 기능을 모듈로 분리함 
-> 중복코드가 줄어들고 각 함수의 역할이 분명해진다.
-> 또한, 모듈 단위 테스트가 가능하여 에러도 줄어든다.
2) 모듈을 분리해 선언
3) 모듈을 외부로 공개함

8.1.2 내부 모듈과 외부 모듈

1) 내부 모듈 (internal module) : namespace

global namespace 와 분리된 namespace 단위의 이름 공간이다. 
같은 namespace 에서는 파일 A가 파일 B에 선언된 모듈을 참조할 수 있는데,
이때 별도의 참조문을 선언할 필요가 없다. 
같은 namespace 내에서는 파일명이 다르더라도 변수, 함수, 클래스 이름이 중복될 수 없다. 

2) 외부 모듈 (external module) : export 하여 외부로 공개된 모듈
변수, 함수, 클래스, 네임스페이스 를 export 키워드를 이용해 외부 모듈로 선언할 수 있다. 

TypeScript는 모듈 선언과 모듈 호출에 있어 ES2015 모듈을 지원합니다.
--module 옵션으로 특정 모듈 형식을 통해 특정 모듈 형식으로 변환할 수 있습니다. 


8.2 네임스페이스

namespace와 module은 동작과 기능상의 차이가 없고, 컴파일 결과도 같습니다. 

namespace 하나를 여러 파일에 선언할 때
참조 경로를 추가해야 하는 상황이 있습니다. 

/// car1.ts/>

파일 상단에 명시적 참조 경로를 선언해줘야 합니다.
하지만, 이 경우 Javascript 파일로 컴파일 되었을때
참조 경로가 주석으로 처리되어 제 기능을 할 수가 없습니다. 
올바른 결과를 위해선 두 파일을 합쳐 컴파일 해야 합니다. 

이를 해결하기 위해,
namespace를 export 하여 module로 선언하여 사용합니다.
모듈로 선언된 네임스페이스는 import 를 통해 
Javascript 로 컴파일된 뒤에도 명시적으로 모듈 호출을 할 수 있습니다. 

export namespace Car {...}

import * as ns from "./car1";

만약 Car namespace module이 여러 파일에 걸쳐 선언됐다면 같은 이름으로 import 할 수 없기 때문에
다음과 같이 별칭을 추가해 이름을 구분해줘야 합니다. 

import * as ns from "./car1";
import * as ns2 from "./car2";


8.2.4 네임스페이스 모듈

-------------------------------------------------
// car1.ts
export namespace Car {
    export let auto: boolean = false;
    export interface ICar {
        name: string;
        vendor: string;
    }
}
// car2.ts
import * as ns from "./car1";
namespace Car {
    let wheels: number;
    console.log(ns.Car.auto);
    class Taxi implements ns.Car.ICar {
        name: string;
        vendor: string;
    }
}
console.log(ns.Car.auto);
-------------------------------------------------

car2.ts 파일이 car1.ts의 모듈을 명시적으로 호출하고, 컴파일 시에도 모듈 호출은 유지됩니다. 


8.2.5. 네임스페이스의 이름 확장

namespace Animal {...}
namespace Animal.Land {...}

.을 이용하면 네임스페이스간에 계층을 만들 수 있습니다. 

Animal.Land 에서 Animal 의 모듈함수를 다음과 같이 호출할 수 있습니다.

Animal.run();

반대로 Animal 에서 Animal.Land 의 요소는 호출할 수 없습니다.
둘은 서로 다른 별개의 이름공간이기 때문입니다. 

-------------------------------------------------
// 동물
namespace Animal {
    export function run() {
        console.log("동물이 달립니다!");
    }
}
// 육상 동물
namespace Animal.Land {
    Animal.run();
    export function run() {
        console.log("육상 동물 이 달립니다!");
    }
}
// 애완 동물
namespace Animal.Land.Pet {
    Animal.Land.run();
    export function run() {
        console.log("애완 동물이 달립니다!");
    }
    // 고양이 클래스
    export class cat {
        run() {
            Animal.Land.Pet.run();
        }
    }
}

let cat = new (Animal.Land.Pet).cat();
cat.run();

-------------------------------------------------

8.3 모듈의 이해와 사용

-------------------------------------------------
// export.ts
export interface ICard { }
export function saveInfo(card: ICard, name: string) { }
// load.ts
import { ICard, saveInfo } from "./export";
let card: ICard = {};
saveInfo(card, "happy");
-------------------------------------------------