문서의 이전 판입니다!
용어에 대한 노트: TypeScript 1.5에서 기록해둘 만큼 중요한 명명법 변경이 있었습니다. “내부 모듈(Internal modules)”은 “네임스페이스”가 되었습니다. “외부 모듈(External modules)”은 이제 간단하게 “모듈(modules)”이 되어 ECMAScript 2015의 용어와 맞췄습니다. (module X {는namespace X {와 동일하며 후자가 선호됩니다.)
ECMAScript 2015부터 JavaScript에는 모듈 개념이 있습니다. TypeScript는 이 개념을 공유합니다.
모듈은 전역 범위가 아닌 자체 범위 내에서 실행됩니다. 이는 모듈에서 선언 된 변수, 함수, 클래스 등이 내보내기 양식 중 하나를 사용하여 명시 적으로 내보내지지 않으면 모듈 외부에서 볼 수 없음을 의미합니다. 반대로, 다른 모듈에서 내 보낸 변수, 함수, 클래스, 인터페이스 등을 사용하려면 import forms 중 하나를 사용하여 가져와야합니다.
모듈은 선언적입니다. 모듈 간의 관계는 파일 수준에서 가져 오기 및 내보내기 측면에서 지정됩니다.
모듈은 모듈 로더를 사용하여 서로를 가져옵니다. 런타임시 모듈 로더는 모듈을 실행하기 전에 모듈의 모든 종속성을 찾고 실행합니다. 자바 스크립트에서 사용되는 잘 알려진 모듈 로더는 CommonJS모듈용 Node.js로더와 웹 애플리케이션에서 AMD모듈용 RequireJS로더입니다.
TypeScript에서는 ECMAScript 2015와 마찬가지로 최상위 import 또는 export가 포함 된 파일을 모듈로 간주합니다. 반대로, 최상위 import 또는 export 선언이 없는 파일은 내용이 전역 범위에서 사용할 수있는 스크립트로 취급되므로 모듈에서도 마찬가지입니다.
export 키워드를 추가하여 모든 선언 (예 : 변수, 함수, 클래스, 유형 별명 또는 인터페이스)을 내보낼 수 있습니다.
export interface StringValidator { isAcceptable(s: string): boolean; }
import { StringValidator } from "./StringValidator"; export const numberRegexp = /^[0-9]+$/; export class ZipCodeValidator implements StringValidator { isAcceptable(s: string) { return s.length === 5 && numberRegexp.test(s); }
Export 문장은 소비자의 이름을 바꿀 필요가 있을 때 유용하므로 위의 예는 다음과 같이 작성 될 수 있습니다.
class ZipCodeValidator implements StringValidator { isAcceptable(s: string) { return s.length === 5 && numberRegexp.test(s); } } export { ZipCodeValidator }; export { ZipCodeValidator as mainValidator };
종종 모듈은 다른 모듈을 확장하고 일부 기능을 부분적으로 노출합니다. 다시 내보내기는 로컬로 가져 오기하거나 로컬 변수를 가져 오지 않습니다.
export class ParseIntBasedZipCodeValidator { isAcceptable(s: string) { return s.length === 5 && parseInt(s).toString() === s; } } // Export original validator but rename it export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";
선택적으로 모듈은 하나 이상의 모듈을 랩핑하고 export * from “module”를 사용하여 모든 내보내기를 결합 할 수 있습니다.
export * from "./StringValidator"; // exports 'StringValidator' interface export * from "./ZipCodeValidator"; // exports 'ZipCodeValidator' and const 'numberRegexp' class export * from "./ParseIntBasedZipCodeValidator"; // exports the 'ParseIntBasedZipCodeValidator' class // and re-exports 'RegExpBasedZipCodeValidator' as alias // of the 'ZipCodeValidator' class from 'ZipCodeValidator.ts' // module.
가져 오기는 모듈에서 내보내기만큼 쉽습니다. 내 보낸 선언을 가져 오려면 아래 가져 오기 양식 중 하나를 사용하십시오.
import { ZipCodeValidator } from "./ZipCodeValidator"; let myValidator = new ZipCodeValidator();
imports는 또한 개명가능하다.
import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
let myValidator = new ZCV();
import는 전체 module을 한 변수로 받아서 export된 module을 접근할 수 있다.
import * as validator from "./ZipCodeValidator"; let myValidator = new validator.ZipCodeValidator();
권장 사항은 아니지만 일부 모듈은 다른 모듈에서 사용할 수있는 일부 전역 상태를 설정합니다. 이 모듈에는 수출이 없거나 소비자가 수출에 관심이 없습니다. 이러한 모듈을 가져 오려면 다음을 사용하십시오.
import "./my-module.js";
각 모듈은 선택적으로 default 내보내기를 내보낼 수 있습니다. default 내보내기는 키워드 default로 표시됩니다. 모듈 당 하나의 default 내보내기 만있을 수 있습니다. default import는 다른 import form을 사용하여 가져옵니다.
default 내보내기은 정말 편리합니다. 예를 들어, jQuery와 같은 라이브러리에는 jQuery 또는 $의 기본 내보내기가있을 수 있습니다. $ 또는 jQuery라는 이름으로 가져올 수도 있습니다.
declare let $: JQuery; export default $;
import $ from "jquery"; $("button.continue").html("Next Step...");
클래스 및 함수 선언은 기본 내보내기로 직접 작성 될 수 있습니다. 기본 내보내기 클래스 및 함수 선언 이름은 선택 사항입니다.
export default class ZipCodeValidator { static numberRegexp = /^[0-9]+$/; isAcceptable(s: string) { return s.length === 5 && ZipCodeValidator.numberRegexp.test(s); } }
import validator from "./ZipCodeValidator"; let myValidator = new validator();
or
const numberRegexp = /^[0-9]+$/; export default function (s: string) { return s.length === 5 && numberRegexp.test(s); }
import validate from "./StaticZipCodeValidator"; let strings = ["Hello", "98052", "101"]; // Use function validate string.forEach(s => { console.log(`"${s}" ${validate(s) ? " matches" : " does not match"}`); });
default내보내기는 값도 가능하다.
export default "123";
import num from "./OneTwoThree"; console.log(num); // "123"
CommonJS와 AMD 모두 일반적으로 모듈의 모든 내보내기를 포함하는 exports 개체 개념을 가지고 있습니다.
또한 exports 개체를 사용자 지정 단일 개체로 바꾸는 기능도 지원합니다. 기본 내보내기는 이 동작을 대신하는 역할을합니다. 그러나 두 개는 호환되지 않습니다. TypeScript는 일반적인 CommonJS 및 AMD 워크 플로우를 모델링하기 위해 export =를 지원합니다.
export = 구문은 모듈에서 내 보낸 단일 객체를 지정합니다. 클래스, 인터페이스, 네임 스페이스, 함수 또는 열거 형이 될 수 있습니다.
export =를 사용하여 모듈을 내보낼 때, 모듈 가져 오기에는 TypeScript 특정 import module = require ( “module”)을 사용해야합니다.
let numberRegexp = /^[0-9]+$/; class ZipCodeValidator { isAcceptable(s: string) { return s.length === 5 && numberRegexp.test(s); } } export = ZipCodeValidator;
import zip = require("./ZipCodeValidator"); // Some samples to try let strings = ["Hello", "98052", "101"]; // Validators to use let validator = new zip(); // Show whether each string passed each validator strings.forEach(s => { console.log(`"${ s }" - ${ validator.isAcceptable(s) ? "matches" : "does not match" }`); });
컴파일하는 동안 지정된 모듈 타겟에 따라 컴파일러는 Node.js (CommonJS), require.js (AMD), UMD, SystemJS 또는 ECMAScript 2015 네이티브 모듈 (ES6) 모듈로드 시스템에 적합한 코드를 생성합니다. 생성 된 코드에서 define, require 및 register 호출에 대한 자세한 내용은 각 모듈 로더에 대한 설명서를 참조하십시오.
이 간단한 예제는 가져 오기 및 내보내기 중에 사용 된 이름이 모듈 로딩 코드로 어떻게 변환되는지 보여줍니다.
import m = require("mod") export let t = m.something + 1;
define(["require", "exports", "./mod"], function (require, exports, mod_1) { exports.t = mod_1.something + 1; });
var mod_1 = require("./mod"); exports.t = mod_1.something + 1;
(function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "./mod"], factory); } })(function (require, exports) { var mod_1 = require("./mod"); exports.t = mod_1.something + 1; });
System.register(["./mod"], function(exports_1) { var mod_1; var t; return { setters:[ function (mod_1_1) { mod_1 = mod_1_1; }], execute: function() { exports_1("t", t = mod_1.something + 1); } } });
import { something } from "./mod"; export var t = something + 1;
아래에서는 앞의 예제에서 사용 된 유효성 검사기 구현을 통합하여 각 모듈에서 하나의 명명 된 내보내기 만 내보내도록했습니다.
컴파일하려면 명령 줄에 모듈 대상을 지정해야합니다. Node.js의 경우 –module commonjs를 사용하십시오. require.js에 대해 –module amd를 사용하십시오.
예 :
tsc --module commonjs Test.ts
컴파일되면 각 모듈은 별도의 .js 파일이됩니다. 참조 태그와 마찬가지로 컴파일러는 import 문을 따라 종속 파일을 컴파일합니다.
export interface StringValidator { isAcceptable(s: string): boolean; }
import { StringValidator } from "./Validation"; const lettersRegexp = /^[A-Za-z]+$/; export class LettersOnlyValidator implements StringValidator { isAcceptable(s: string) { return lettersRegexp.test(s); } }
import { StringValidator } from "./Validation"; const numberRegexp = /^[0-9]+$/; export class ZipCodeValidator implements StringValidator { isAcceptable(s: string) { return s.length === 5 && numberRegexp.test(s); } }
import { StringValidator } from "./Validation"; import { ZipCodeValidator } from "./ZipCodeValidator"; import { LettersOnlyValidator } from "./LettersOnlyValidator"; // Some samples to try let strings = ["Hello", "98052", "101"]; // Validators to use let validators: { [s: string]: StringValidator; } = {}; validators["ZIP code"] = new ZipCodeValidator(); validators["Letters only"] = new LettersOnlyValidator(); // Show whether each string passed each validator strings.forEach(s => { for (let name in validators) { console.log(`"${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name }`); } });
경우에 따라서 어떤 조건에서만 모듈을 로드를 원할 수 있습니다. TypeScript에서는 타입 안전성을 유지하면서 모듈 로더를 직접 호출 할 수 있도록 다음과 같은 고급로드 시나리오를 구현하기 위해 아래에 표시된 패턴을 사용할 수 있습니다.
컴파일러는 각 모듈이 방출된(emitted) JavaScript에서 사용되는지 여부를 감지합니다. 모듈 식별자가 타입 주석의 일부로 만 사용되고 식이 아닌 경우에는 해당 모듈에 대한 호출이 필요하지 않습니다. 사용하지 않는 참조를 제거하면 좋은 성능 최적화를 얻을 수 있으며 해당 모듈을 선택적으로 로드 할 수 있습니다.
이 패턴의 핵심 아이디어는 import id = require(“…”) 문을 사용하면 모듈에 의해 노출 된 유형에 액세스 할 수 있다는 것입니다. 모듈 로더는 아래의 if 블록 에서처럼 동적으로 호출됩니다 (require를 통해). 이는 레퍼런스-엘리먼 지 최적화를 활용하므로 필요한 경우에만 모듈이로드됩니다. 이 패턴이 작동하려면 import를 통해 정의 된 기호가 타입 위치에서만 사용되어야합니다 (즉, 자바 스크립트로 전송되는 위치에 절대 사용되지 않음).
타입 안전성을 유지하기 위해 typeof 키워드를 사용할 수 있습니다. typeof 키워드를 타입 위치에서 사용하면 값 타입 (이 경우 모듈 타입)이 생성됩니다.
declare function require(moduleName: string): any; import { ZipCodeValidator as Zip } from "./ZipCodeValidator"; if (needZipValidation) { let ZipCodeValidator: typeof Zip = require("./ZipCodeValidator"); let validator = new ZipCodeValidator(); if (validator.isAcceptable("...")) { /* ... */ } }
declare function require(moduleNames: string[], onLoad: (...args: any[]) => void): void; import * as Zip from "./ZipCodeValidator"; if (needZipValidation) { require(["./ZipCodeValidator"], (ZipCodeValidator: typeof Zip) => { let validator = new ZipCodeValidator.ZipCodeValidator(); if (validator.isAcceptable("...")) { /* ... */ } }); }
declare const System: any; import { ZipCodeValidator as Zip } from "./ZipCodeValidator"; if (needZipValidation) { System.import("./ZipCodeValidator").then((ZipCodeValidator: typeof Zip) => { var x = new ZipCodeValidator(); if (x.isAcceptable("...")) { /* ... */ } }); }
TypeScript로 작성되지 않은 라이브러리의 모양을 설명하려면 라이브러리가 노출하는 API를 선언해야합니다.
구현을 “ambient”으로 정의하지 않는 선언을 호출합니다. 일반적으로 .d.ts파일에 정의되어 있습니다. C/C ++에 익숙하다면이 파일을 .h 파일로 생각할 수 있습니다. 몇 가지 예를 살펴 보겠습니다.
Node.js에서 대부분의 작업은 하나 이상의 모듈을로드하여 수행됩니다. 최상위 수준의 내보내기 선언을 사용하여 각 모듈을 자체 .d.ts 파일로 정의 할 수 있지만 더 큰 .d.ts 파일로 작성하는 것이 더 편리합니다. 그렇게하기 위해, 우리는 앰비언트 네임 스페이스와 비슷한 구조를 사용하지만, module 키워드와 추후 가져올 수있는 모듈의 인용된 이름을 사용합니다.
예 :
declare module "url" { export interface Url { protocol?: string; hostname?: string; pathname?: string; } export function parse(urlStr: string, parseQueryString?, slashesDenoteHost?): Url; } declare module "path" { export function normalize(p: string): string; export function join(...paths: any[]): string; export var sep: string; }
이제 /// <reference> node.d.ts</wrap>참조할 수 있고 import url = require(“url”); 또는 import * as URL from “url”을 사용하여 모듈을 로드할 수 있다.