Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Latest commit

Β 

History

History
860 lines (627 loc) Β· 30 KB

modules.md

File metadata and controls

860 lines (627 loc) Β· 30 KB

μ†Œκ°œ (Introduction)

ECMAScript 2015λΆ€ν„° JavaScriptμ—λŠ” λͺ¨λ“ˆ κ°œλ…μ΄ μžˆμŠ΅λ‹ˆλ‹€. TypeScriptλŠ” 이 κ°œλ…μ„ κ³΅μœ ν•©λ‹ˆλ‹€.

λͺ¨λ“ˆμ€ μ „μ—­ μŠ€μ½”ν”„κ°€ μ•„λ‹Œ 자체 μŠ€μ½”ν”„ λ‚΄μ—μ„œ μ‹€ν–‰λ©λ‹ˆλ‹€; 즉 λͺ¨λ“ˆ λ‚΄μ—μ„œ μ„ μ–Έλœ λ³€μˆ˜, ν•¨μˆ˜, 클래슀 등은 export 양식 쀑 ν•˜λ‚˜λ₯Ό μ‚¬μš©ν•˜μ—¬ λͺ…μ‹œμ μœΌλ‘œ export ν•˜μ§€ μ•ŠλŠ” ν•œ λͺ¨λ“ˆ μ™ΈλΆ€μ—μ„œ 보이지 μ•ŠμŠ΅λ‹ˆλ‹€. λ°˜λŒ€λ‘œ λ‹€λ₯Έ λͺ¨λ“ˆμ—μ„œ export ν•œ λ³€μˆ˜, ν•¨μˆ˜, 클래슀, μΈν„°νŽ˜μ΄μŠ€ 등을 μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” import 양식 쀑 ν•˜λ‚˜λ₯Ό μ‚¬μš©ν•˜μ—¬ import ν•΄μ•Ό ν•©λ‹ˆλ‹€.

λͺ¨λ“ˆμ€ μ„ μ–Έν˜•μž…λ‹ˆλ‹€; λͺ¨λ“ˆ κ°„μ˜ κ΄€κ³„λŠ” 파일 μˆ˜μ€€μ˜ imports 및 exports κ΄€μ μ—μ„œ μ§€μ •λ©λ‹ˆλ‹€.

λͺ¨λ“ˆμ€ λͺ¨λ“ˆ λ‘œλ”λ₯Ό μ‚¬μš©ν•˜μ—¬ λ‹€λ₯Έ λͺ¨λ“ˆμ„ import ν•©λ‹ˆλ‹€. λŸ°νƒ€μž„ μ‹œ λͺ¨λ“ˆ λ‘œλ”λŠ” λͺ¨λ“ˆμ„ μ‹€ν–‰ν•˜κΈ° 전에 λͺ¨λ“ˆμ˜ λͺ¨λ“  μ˜μ‘΄μ„±μ„ μ°Ύκ³  μ‹€ν–‰ν•΄μ•Ό ν•©λ‹ˆλ‹€. JavaScriptμ—μ„œ μ‚¬μš©ν•˜λŠ” 유λͺ…ν•œ λͺ¨λ“ˆ λ‘œλ”λ‘œλŠ” CommonJS λͺ¨λ“ˆ 용 Node.js의 λ‘œλ”μ™€ μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ AMD λͺ¨λ“ˆ 용 RequireJS λ‘œλ”κ°€ μžˆμŠ΅λ‹ˆλ‹€.

ECMAScript 2015와 λ§ˆμ°¬κ°€μ§€λ‘œ TypeScriptλŠ” μ΅œμƒμœ„ μˆ˜μ€€μ˜ import ν˜Ήμ€ exportκ°€ ν¬ν•¨λœ λͺ¨λ“  νŒŒμΌμ„ λͺ¨λ“ˆλ‘œ κ°„μ£Όν•©λ‹ˆλ‹€. λ°˜λŒ€λ‘œ μ΅œμƒμœ„ μˆ˜μ€€μ˜ import ν˜Ήμ€ export 선언이 μ—†λŠ” νŒŒμΌμ€ μ „μ—­ μŠ€μ½”ν”„μ—μ„œ μ‚¬μš©ν•  수 μžˆλŠ” 슀크립트둜 μ²˜λ¦¬λ©λ‹ˆλ‹€(λͺ¨λ“ˆμ—μ„œλ„ λ§ˆμ°¬κ°€μ§€).

Export

μ„ μ–Έ export ν•˜κΈ° (Exporting a declaration)

export ν‚€μ›Œλ“œλ₯Ό μΆ”κ°€ν•˜μ—¬ λͺ¨λ“  μ„ μ–Έ (λ³€μˆ˜, ν•¨μˆ˜, 클래슀, νƒ€μž… 별칭, μΈν„°νŽ˜μ΄μŠ€)λ₯Ό export ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

StringValidator.ts
export interface StringValidator {
    isAcceptable(s: string): boolean;
}
ZipCodeValidator.ts
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 λ¬Έ (Export statements)

Export 문은 μ‚¬μš©μžλ₯Ό μœ„ν•΄ export ν•  이름을 λ°”κΏ”μ•Ό ν•  λ•Œ νŽΈλ¦¬ν•©λ‹ˆλ‹€. μœ„μ˜ μ˜ˆμ œλŠ” λ‹€μŒκ³Ό 같이 μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

class ZipCodeValidator implements StringValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}
export { ZipCodeValidator };
export { ZipCodeValidator as mainValidator };

Re-export ν•˜κΈ° (Re-exports)

μ’…μ’… λͺ¨λ“ˆμ€ λ‹€λ₯Έ λͺ¨λ“ˆμ„ ν™•μž₯ν•˜κ³  일뢀 κΈ°λŠ₯을 λΆ€λΆ„μ μœΌλ‘œ λ…ΈμΆœν•©λ‹ˆλ‹€. Re-export ν•˜κΈ°λŠ” μ§€μ—­μ μœΌλ‘œ import ν•˜κ±°λ‚˜, 지역 λ³€μˆ˜λ₯Ό λ„μž…ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

ParseIntBasedZipCodeValidator.ts
export class ParseIntBasedZipCodeValidator {
    isAcceptable(s: string) {
        return s.length === 5 && parseInt(s).toString() === s;
    }
}

// κΈ°μ‘΄ validator의 이름을 λ³€κ²½ ν›„ export
export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";

μ„ νƒμ μœΌλ‘œ, ν•˜λ‚˜μ˜ λͺ¨λ“ˆμ€ ν•˜λ‚˜ ν˜Ήμ€ μ—¬λŸ¬ 개의 λͺ¨λ“ˆμ„ κ°μŒ€ 수 있고, export * from "module" ꡬ문을 μ‚¬μš©ν•΄ export ν•˜λŠ” 것을 λͺ¨λ‘ κ²°ν•©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

AllValidators.ts
export * from "./StringValidator"; // 'StringValidator' μΈν„°νŽ˜μ΄μŠ€λ₯Ό 내보냄
export * from "./ZipCodeValidator";  // 'ZipCodeValidator' 와 const 'numberRegexp' 클래슀λ₯Ό 내보냄
export * from "./ParseIntBasedZipCodeValidator"; // 'ParseIntBasedZipCodeValidator' 클래슀λ₯Ό 내보냄
                                                 // 'ZipCodeValidator.ts' λͺ¨λ“ˆ 에 μžˆλŠ”
                                                 // 'ZipCodeValidator' 클래슀λ₯Ό
                                                 // 'RegExpBasedZipCodeValidator' λΌλŠ” λ³„μΉ­μœΌλ‘œ λ‹€μ‹œ 내보냄

Import

importλŠ” λͺ¨λ“ˆμ—μ„œ export 만큼 μ‰½μŠ΅λ‹ˆλ‹€. export ν•œ 선언은 μ•„λž˜μ˜ import 양식 쀑 ν•˜λ‚˜λ₯Ό μ‚¬μš©ν•˜μ—¬ import ν•©λ‹ˆλ‹€:

λͺ¨λ“ˆμ—μ„œ 단일 exportλ₯Ό import ν•˜κΈ° (Import a single export from a module)

import { ZipCodeValidator } from "./ZipCodeValidator";

let myValidator = new ZipCodeValidator();

이름을 μˆ˜μ •ν•΄μ„œ import ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
let myValidator = new ZCV();

전체 λͺ¨λ“ˆμ„ 단일 λ³€μˆ˜λ‘œ import ν•΄μ„œ, λͺ¨λ“ˆ exports 접근에 μ‚¬μš©ν•˜κΈ° (Import the entire module into a single variable, and use it to access the module exports)

import * as validator from "./ZipCodeValidator";
let myValidator = new validator.ZipCodeValidator();

λΆ€μˆ˜νš¨κ³Όλ§Œμ„ μœ„ν•΄ λͺ¨λ“ˆ import ν•˜κΈ° (Import a module for side-effects only)

ꢌμž₯λ˜μ§€λŠ” μ•Šμ§€λ§Œ, 일뢀 λͺ¨λ“ˆμ€ λ‹€λ₯Έ λͺ¨λ“ˆμ—μ„œ μ‚¬μš©ν•  수 μžˆλ„λ‘ 일뢀 μ „μ—­ μƒνƒœλ‘œ μ„€μ •ν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ λͺ¨λ“ˆμ€ μ–΄λ–€ exports도 μ—†κ±°λ‚˜, μ‚¬μš©μžκ°€ exports에 관심이 μ—†μŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ λͺ¨λ“ˆμ„ import ν•˜κΈ° μœ„ν•΄, λ‹€μŒμ²˜λŸΌ μ‚¬μš©ν•˜μ„Έμš”:

import "./my-module.js"

νƒ€μž… import ν•˜κΈ° (Importing Types)

TypeScript 3.8 μ΄μ „μ—λŠ” importλ₯Ό μ‚¬μš©ν•˜μ—¬ νƒ€μž…μ„ import ν•  수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. TypeScript 3.8μ—μ„œλŠ” import λ¬Έ ν˜Ήμ€ import type을 μ‚¬μš©ν•˜μ—¬ νƒ€μž…μ„ import ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

// λ™μΌν•œ importλ₯Ό μž¬μ‚¬μš©ν•˜κΈ°
import {APIResponseType} from "./api";

// λͺ…μ‹œμ μœΌλ‘œ import type을 μ‚¬μš©ν•˜κΈ°
import type {APIResponseType} from "./api";

import type은 항상 JavaScriptμ—μ„œ 제거되며, 바벨 같은 λ„κ΅¬λŠ” isolatedModules 컴파일러 ν”Œλž˜κ·Έλ₯Ό 톡해 μ½”λ“œμ— λŒ€ν•΄ 더 λ‚˜μ€ 가정을 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 3.8 릴리즈 μ •λ³΄μ—μ„œ 더 λ§Žμ€ 정보λ₯Ό 읽을 수 μžˆμŠ΅λ‹ˆλ‹€.

Default exports

각 λͺ¨λ“ˆμ€ μ„ νƒμ μœΌλ‘œ default exportλ₯Ό export ν•  수 μžˆμŠ΅λ‹ˆλ‹€. default exportλŠ” default ν‚€μ›Œλ“œλ‘œ ν‘œμ‹œλ©λ‹ˆλ‹€; λͺ¨λ“ˆλ‹Ή ν•˜λ‚˜μ˜ default export만 κ°€λŠ₯ν•©λ‹ˆλ‹€. default exportλŠ” λ‹€λ₯Έ import 양식을 μ‚¬μš©ν•˜μ—¬ import ν•©λ‹ˆλ‹€.

default exportsλŠ” 정말 νŽΈλ¦¬ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ jQuery와 같은 λΌμ΄λΈŒλŸ¬λ¦¬λŠ” jQuery ν˜Ήμ€ $와 같은 default exportλ₯Ό κ°€μ§ˆ 수 있으며, $λ‚˜ jQuery와 같은 μ΄λ¦„μœΌλ‘œ importν•  수 μžˆμŠ΅λ‹ˆλ‹€.

declare let $: JQuery;
export default $;
App.ts
import $ from "jquery";

$("button.continue").html( "Next Step..." );

클래슀 및 ν•¨μˆ˜ 선언은 default exports둜 직접 μž‘μ„±λ  수 μžˆμŠ΅λ‹ˆλ‹€. default export 클래슀 및 ν•¨μˆ˜ μ„ μ–Έ 이름은 선택사항 μž…λ‹ˆλ‹€.

ZipCodeValidator.ts
export default class ZipCodeValidator {
    static numberRegexp = /^[0-9]+$/;
    isAcceptable(s: string) {
        return s.length === 5 && ZipCodeValidator.numberRegexp.test(s);
    }
}
Test.ts
import validator from "./ZipCodeValidator";

let myValidator = new validator();

ν˜Ήμ€

StaticZipCodeValidator.ts
const numberRegexp = /^[0-9]+$/;

export default function (s: string) {
    return s.length === 5 && numberRegexp.test(s);
}
Test.ts
import validate from "./StaticZipCodeValidator";

let strings = ["Hello", "98052", "101"];

// validate ν•¨μˆ˜ μ‚¬μš©ν•˜κΈ°
strings.forEach(s => {
  console.log(`"${s}" ${validate(s) ? "matches" : "does not match"}`);
});

default exportsλŠ” 값도 κ°€λŠ₯ν•©λ‹ˆλ‹€:

OneTwoThree.ts
export default "123";
Log.ts
import num from "./OneTwoThree";

console.log(num); // "123"

x둜 λͺ¨λ‘ export ν•˜κΈ° (Export all as x)

TypeScript 3.8μ—μ„œλŠ” λ‹€μŒ 이름이 λ‹€λ₯Έ λͺ¨λ“ˆλ‘œ re-export 될 λ•Œ λ‹¨μΆ•μ–΄μ²˜λŸΌ export * as nsλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

export * as utilities from "./utilities";

λͺ¨λ“ˆμ—μ„œ λͺ¨λ“  μ˜μ‘΄μ„±μ„ 가져와 exportν•œ ν•„λ“œλ‘œ λ§Œλ“€λ©΄, λ‹€μŒκ³Ό 같이 importν•  수 μžˆμŠ΅λ‹ˆλ‹€:

import { utilities } from "./index";

export =와 import = require() (export = and import = require())

CommonJS와 AMD λ‘˜ λ‹€ 일반적으둜 λͺ¨λ“ˆμ˜ λͺ¨λ“  exportsλ₯Ό ν¬ν•¨ν•˜λŠ” exports 객체의 κ°œλ…μ„ 가지고 μžˆμŠ΅λ‹ˆλ‹€.

λ˜ν•œ exports 객체λ₯Ό μ‚¬μš©μž μ •μ˜ 단일 객체둜 λŒ€μ²΄ν•˜λŠ” κΈ°λŠ₯도 μ§€μ›ν•©λ‹ˆλ‹€. default exportsλŠ” 이 λ™μž‘μ—μ„œ λŒ€μ²΄ 역할을 ν•©λ‹ˆλ‹€; ν•˜μ§€λ§Œ λ‘˜μ€ ν˜Έν™˜λ˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€. TypeScriptλŠ” 기쑴의 CommonJS와 AMD μ›Œν¬ν”Œλ‘œμš°λ₯Ό λͺ¨λΈλ§ ν•˜κΈ° μœ„ν•΄ export =λ₯Ό μ§€μ›ν•©λ‹ˆλ‹€.

export = ꡬ문은 λͺ¨λ“ˆμ—μ„œ exportλ˜λŠ” 단일 객체λ₯Ό μ§€μ •ν•©λ‹ˆλ‹€. 클래슀, μΈν„°νŽ˜μ΄μŠ€, λ„€μž„μŠ€νŽ˜μ΄μŠ€, ν•¨μˆ˜ ν˜Ήμ€ μ—΄κ±°ν˜•μ΄ 될 수 μžˆμŠ΅λ‹ˆλ‹€.

export = λ₯Ό μ‚¬μš©ν•˜μ—¬ λͺ¨λ“ˆμ„ exportν•  λ•Œ, TypeScript에 νŠΉμ •ν•œ import module = require("module")λ₯Ό μ‚¬μš©ν•˜μ—¬ λͺ¨λ“ˆμ„ 가져와야 ν•©λ‹ˆλ‹€.

ZipCodeValidator.ts
let numberRegexp = /^[0-9]+$/;
class ZipCodeValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}
export = ZipCodeValidator;
Test.ts
import zip = require("./ZipCodeValidator");

// μ‹œν—˜μš© μƒ˜ν”Œ
let strings = ["Hello", "98052", "101"];

// μ‚¬μš©ν•  Validators
let validator = new zip();

// 각 λ¬Έμžμ—΄μ΄ 각 validatorλ₯Ό ν†΅κ³Όν–ˆλŠ”μ§€ λ³΄μ—¬μ€λ‹ˆλ‹€
strings.forEach(s => {
  console.log(`"${ s }" - ${ validator.isAcceptable(s) ? "matches" : "does not match" }`);
});

λͺ¨λ“ˆμ„ μœ„ν•œ μ½”λ“œ 생성 (Code Generation for Modules)

컴파일 μ€‘μ—λŠ” μ§€μ •λœ λͺ¨λ“ˆ λŒ€μƒμ— 따라 μ»΄νŒŒμΌλŸ¬λŠ” Node.js (CommonJS), require.js (AMD), UMD, SystemJS, λ˜λŠ” ECMAScript 2015 native modules (ES6) λͺ¨λ“ˆ-λ‘œλ”© μ‹œμŠ€ν…œμ— μ ν•©ν•œ μ½”λ“œλ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. μƒμ„±λœ μ½”λ“œμ˜ define, require 그리고 register 호좜 κΈ°λŠ₯에 λŒ€ν•œ μžμ„Έν•œ μ •λ³΄λŠ” 각 λͺ¨λ“ˆ λ‘œλ”μ˜ λ¬Έμ„œλ₯Ό ν™•μΈν•˜μ„Έμš”.

이 κ°„λ‹¨ν•œ μ˜ˆμ œλŠ” import 및 export ν•˜κΈ° 쀑에 μ‚¬μš©λœ 이름이 λͺ¨λ“ˆ λ‘œλ”© μ½”λ“œλ‘œ λ³€ν™˜λ˜λŠ” 방법을 λ³΄μ—¬μ€λ‹ˆλ‹€.

SimpleModule.ts
import m = require("mod");
export let t = m.something + 1;
AMD / RequireJS SimpleModule.js
define(["require", "exports", "./mod"], function (require, exports, mod_1) {
    exports.t = mod_1.something + 1;
});
CommonJS / Node SimpleModule.js
var mod_1 = require("./mod");
exports.t = mod_1.something + 1;
UMD SimpleModule.js
(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 SimpleModule.js
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);
        }
    }
});
Native ECMAScript 2015 modules SimpleModule.js
import { something } from "./mod";
export var t = something + 1;

κ°„λ‹¨ν•œ 예제 (Simple Example)

μ•„λž˜μ—μ„œλŠ” 각 λͺ¨λ“ˆμ—μ„œ 단일 μ΄λ¦„μœΌλ‘œ export ν•˜κΈ° μœ„ν•΄ 이전 μ˜ˆμ œμ—μ„œ μ‚¬μš©ν•œ Validator κ΅¬ν˜„μ„ ν†΅ν•©ν•©λ‹ˆλ‹€.

컴파일 ν•˜λ €λ©΄, λͺ…λ Ή μ€„μ—μ„œ λͺ¨λ“ˆ λŒ€μƒμ„ 지정해야 ν•©λ‹ˆλ‹€. Node.js의 경우, --module commonjsλ₯Ό μ‚¬μš©ν•˜μ„Έμš”; require.js의 경우 --module amdλ₯Ό μ‚¬μš©ν•˜μ„Έμš”. 예λ₯Ό λ“€λ©΄:

tsc --module commonjs Test.ts

컴파일이 되면, 각 λͺ¨λ“ˆμ€ λ³„λ„μ˜ .js파일이 λ©λ‹ˆλ‹€. μ°Έμ‘° νƒœκ·Έμ™€ λ§ˆμ°¬κ°€μ§€λ‘œ, μ»΄νŒŒμΌλŸ¬λŠ” import문을 따라 의쑴적인 νŒŒμΌλ“€μ„ 컴파일 ν•©λ‹ˆλ‹€.

Validation.ts
export interface StringValidator {
    isAcceptable(s: string): boolean;
}
LettersOnlyValidator.ts
import { StringValidator } from "./Validation";

const lettersRegexp = /^[A-Za-z]+$/;

export class LettersOnlyValidator implements StringValidator {
    isAcceptable(s: string) {
        return lettersRegexp.test(s);
    }
}
ZipCodeValidator.ts
import { StringValidator } from "./Validation";

const numberRegexp = /^[0-9]+$/;

export class ZipCodeValidator implements StringValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}
Test.ts
import { StringValidator } from "./Validation";
import { ZipCodeValidator } from "./ZipCodeValidator";
import { LettersOnlyValidator } from "./LettersOnlyValidator";

// μ‹œν—˜μš© μƒ˜ν”Œ
let strings = ["Hello", "98052", "101"];

// μ‚¬μš©ν•  validator
let validators: { [s: string]: StringValidator; } = {};
validators["ZIP code"] = new ZipCodeValidator();
validators["Letters only"] = new LettersOnlyValidator();

// 각 λ¬Έμžμ—΄μ΄ validatorλ₯Ό ν†΅κ³Όν•˜λŠ”μ§€ λ³΄μ—¬μ€Œ
strings.forEach(s => {
    for (let name in validators) {
        console.log(`"${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name }`);
    }
});

선택적 λͺ¨λ“ˆ λ‘œλ”©κ³Ό 기타 κ³ κΈ‰ λ‘œλ”© μ‹œλ‚˜λ¦¬μ˜€ (Optional Module Loading and Other Advanced Loading Scenarios)

상황에 따라 νŠΉμ • μ‘°κ±΄μ—μ„œλ§Œ λͺ¨λ“ˆμ„ λ‘œλ“œν•˜λ„λ‘ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€. TypeScriptμ—μ„œλŠ” μ•„λž˜μ— μžˆλŠ” νŒ¨ν„΄μ„ μ‚¬μš©ν•˜μ—¬ 이 μ‹œλ‚˜λ¦¬μ˜€μ™€ λ‹€λ₯Έ κ³ κΈ‰ λ‘œλ”© μ‹œλ‚˜λ¦¬μ˜€λ₯Ό κ΅¬ν˜„ν•˜μ—¬ νƒ€μž…μ˜ μ•ˆμ „μ„±μ„ μžƒμ§€ μ•Šκ³  λͺ¨λ“ˆ λ‘œλ”λ₯Ό 직접 ν˜ΈμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ»΄νŒŒμΌλŸ¬λŠ” λ…ΈμΆœλœ JavaScript μ•ˆμ—μ„œ 각 λͺ¨λ“ˆμ˜ μ‚¬μš© μ—¬λΆ€λ₯Ό κ°μ§€ν•©λ‹ˆλ‹€. λͺ¨λ“ˆ μ‹λ³„μžκ°€ ν‘œν˜„μ‹μ΄ μ•„λ‹Œ νƒ€μž… ν‘œμ‹œλ‘œλ§Œ μ‚¬μš©λœλ‹€λ©΄ κ·Έ λͺ¨λ“ˆμ— λŒ€ν•œ require ν˜ΈμΆœμ€ λ°œμƒν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μ°Έμ‘°λ₯Ό μ œκ±°ν•˜λ©΄ μ„±λŠ₯을 μ΅œμ ν™”ν•  수 있으며, ν•΄λ‹Ή λͺ¨λ“ˆμ„ μ„ νƒμ μœΌλ‘œ λ‘œλ”© ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

이 νŒ¨ν„΄μ˜ 핡심 μ•„μ΄λ””μ–΄λŠ” import id = require("...") 문을 톡해 λͺ¨λ“ˆλ‘œ λ…ΈμΆœλœ νƒ€μž…μ— 접근이 κ°€λŠ₯ν•˜λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. μ•„λž˜ if 블둝에 λ³΄μ΄λŠ” κ²ƒμ²˜λŸΌ, λͺ¨λ“ˆ λ‘œλ”λŠ” (require을 톡해) λ™μ μœΌλ‘œ ν˜ΈμΆœλ©λ‹ˆλ‹€. 이 κΈ°λŠ₯은 μ°Έμ‘°-제거 μ΅œμ ν™”λ₯Ό ν™œμš©ν•˜λ―€λ‘œ ν•„μš”ν•  λ•Œλ§Œ λͺ¨λ“ˆμ„ λ‘œλ“œν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν•΄λ‹Ή νŒ¨ν„΄μ΄ λ™μž‘ν•˜λ €λ©΄ importλ₯Ό 톡해 μ •μ˜λœ μ‹¬λ²Œμ€ 였직 νƒ€μž… μœ„μΉ˜(즉, JavaScript둜 λ°©μΆœλ˜λŠ” μœ„μΉ˜μ—μ„œλŠ” μ‚¬μš© μ•ˆ 함)μ—μ„œλ§Œ μ‚¬μš©λ˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€.

νƒ€μž… μ•ˆμ „μ„±μ„ μœ μ§€ν•˜κΈ° μœ„ν•΄, typeof ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. typeof ν‚€μ›Œλ“œλŠ” νƒ€μž… μœ„μΉ˜μ—μ„œ μ‚¬μš©λ  λ•ŒλŠ” κ°’μ˜ νƒ€μž…, 이 κ²½μš°μ—λŠ” λͺ¨λ“ˆμ˜ νƒ€μž…μ„ μƒμ„±ν•©λ‹ˆλ‹€.

Node.jsμ—μ„œ 동적 λͺ¨λ“ˆ λ‘œλ”© (Dynamic Module Loading in Node.js)
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("...")) { /* ... */ }
}
μƒ˜ν”Œ: require.jsμ—μ„œ 동적 λͺ¨λ“ˆ λ‘œλ”© (Sample: Dynamic Module Loading in require.js)
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("...")) { /* ... */ }
    });
}
μƒ˜ν”Œ: System.jsμ—μ„œ 동적 λͺ¨λ“ˆ λ‘œλ”© (Sample: Dynamic Module Loading in System.js)
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("...")) { /* ... */ }
    });
}

λ‹€λ₯Έ JavaScript λΌμ΄λΈŒλŸ¬λ¦¬μ™€ ν•¨κ»˜ μ‚¬μš©ν•˜κΈ° (Working with Other JavaScript Libraries)

TypeScript둜 μž‘μ„±λ˜μ§€ μ•Šμ€ 라이브러리의 ν˜•νƒœλ₯Ό μ„€λͺ…ν•˜λ €λ©΄, 라이브러리λ₯Ό λ…ΈμΆœν•˜λŠ” APIλ₯Ό μ„ μ–Έν•΄μ•Ό ν•©λ‹ˆλ‹€.

μš°λ¦¬λŠ” κ΅¬ν˜„μ„ μ •μ˜ν•˜μ§€ μ•Šμ€ 선언을 "ambient"라고 λΆ€λ¦…λ‹ˆλ‹€. 이 선언듀은 일반적으둜 .d.ts νŒŒμΌμ— μ •μ˜λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. C/C++에 μ΅μˆ™ν•˜λ‹€λ©΄, .h 파일이라고 생각할 수 μžˆμŠ΅λ‹ˆλ‹€. λͺ‡ 가지 예제λ₯Ό μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

Ambient λͺ¨λ“ˆ (Ambient Modules)

Node.jsμ—μ„œλŠ” λŒ€λΆ€λΆ„μ˜ μž‘μ—…μ€ ν•˜λ‚˜ μ΄μƒμ˜ λͺ¨λ“ˆμ„ λ‘œλ“œν•˜μ—¬ μˆ˜ν–‰ν•©λ‹ˆλ‹€. μ΅œμƒμœ„-레벨의 내보내기 μ„ μ–ΈμœΌλ‘œ 각 λͺ¨λ“ˆμ„ .d.ts 파일둜 μ •μ˜ν•  수 μžˆμ§€λ§Œ, 더 큰 ν•˜λ‚˜μ˜ .d.ts 파일둜 λͺ¨λ“ˆλ“€μ„ μž‘μ„±ν•˜λŠ” 것이 더 νŽΈλ¦¬ν•©λ‹ˆλ‹€. 이λ₯Ό μœ„ν•΄, ambient λ„€μž„μŠ€νŽ˜μ΄μŠ€μ™€ μœ μ‚¬ν•œ ꡬ쑰λ₯Ό μ‚¬μš©ν•˜μ§€λ§Œ, λ‚˜μ€‘μ— import ν•  수 μžˆλŠ” 인용된 λͺ¨λ“ˆ 이름과 module ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€λ©΄:

node.d.ts (κ°„λ‹¨ν•œ 발췌)
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λ₯Ό μˆ˜ν–‰ν•œ λ‹€μŒ, import url = require("url"); λ˜λŠ” import * as URL from "url"을 μ‚¬μš©ν•˜μ—¬ λͺ¨λ“ˆμ„ λ‘œλ“œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

/// <reference path="node.d.ts"/>
import * as URL from "url";
let myUrl = URL.parse("http://www.typescriptlang.org");

속기 ambient λͺ¨λ“ˆ (Shorthand ambient modules)

μƒˆλ‘œμš΄ λͺ¨λ“ˆμ„ μ‚¬μš©ν•˜κΈ° 전에 선언을 μž‘μ„±ν•˜μ§€ μ•ŠλŠ” 경우, 속기 μ„ μ–Έ(shorthand declaration)을 μ‚¬μš©ν•˜μ—¬ λΉ λ₯΄κ²Œ μ‹œμž‘ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

declarations.d.ts
declare module "hot-new-module";

속기 λͺ¨λ“ˆλ‘œλΆ€ν„° λͺ¨λ“  importsλŠ” any νƒ€μž…μ„ κ°€μ§‘λ‹ˆλ‹€.

import x, {y} from "hot-new-module";
x(y);

μ™€μΌλ“œμΉ΄λ“œ λͺ¨λ“ˆ μ„ μ–Έ (Wildcard module declarations)

SystemJSλ‚˜ AMD와 같은 λͺ¨λ“ˆ λ‘œλ”λŠ” λΉ„-JavaScirpt λ‚΄μš©μ„ import ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이 λ‘˜μ€ 일반적으둜 접두사 λ˜λŠ” 접미사λ₯Ό μ‚¬μš©ν•˜μ—¬ νŠΉμˆ˜ν•œ λ‘œλ”© 의미λ₯Ό ν‘œμ‹œν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ 경우λ₯Ό 닀루기 μœ„ν•΄ μ™€μΌλ“œμΉ΄λ“œ λͺ¨λ“ˆ 선언을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

declare module "*!text" {
    const content: string;
    export default content;
}
// μΌλΆ€λŠ” λ‹€λ₯Έ λ°©λ²•μœΌλ‘œ μ‚¬μš©ν•©λ‹ˆλ‹€.
declare module "json!*" {
    const value: any;
    export default value;
}

이제 "*!text" λ‚˜ "json!*"와 μΌμΉ˜ν•˜λŠ” 것듀을 import ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

import fileContent from "./xyz.txt!text";
import data from "json!http://example.com/data.json";
console.log(data, fileContent);

UMD λͺ¨λ“ˆ (UMD modules)

일뢀 λΌμ΄λΈŒλŸ¬λ¦¬λŠ” λ§Žμ€ λͺ¨λ“ˆ λ‘œλ”μ—μ„œ μ‚¬μš©λ˜κ±°λ‚˜, λͺ¨λ“ˆ λ‘œλ”© (μ „μ—­ λ³€μˆ˜) 없이 μ‚¬μš©λ˜λ„λ‘ μ„€κ³„λ˜μ—ˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό UMD λͺ¨λ“ˆμ΄λΌκ³  ν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ λΌμ΄λΈŒλŸ¬λ¦¬λŠ” importλ‚˜ μ „μ—­ λ³€μˆ˜λ₯Ό 톡해 μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€λ©΄:

math-lib.d.ts
export function isPrime(x: number): boolean;
export as namespace mathLib;

λΌμ΄λΈŒλŸ¬λ¦¬λŠ” λͺ¨λ“ˆ λ‚΄μ—μ„œ import둜 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

import { isPrime } from "math-lib";
isPrime(2);
mathLib.isPrime(2); // 였λ₯˜: λͺ¨λ“ˆ λ‚΄λΆ€μ—μ„œ μ „μ—­ μ •μ˜λ₯Ό μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

μ „μ—­ λ³€μˆ˜λ‘œλ„ μ‚¬μš©ν•  수 μžˆμ§€λ§Œ, 슀크립트 λ‚΄μ—μ„œλ§Œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. (μŠ€ν¬λ¦½νŠΈλŠ” importsλ‚˜ exportsκ°€ μ—†λŠ” νŒŒμΌμž…λ‹ˆλ‹€.)

mathLib.isPrime(2);

λͺ¨λ“ˆ ꡬ쑰화에 λŒ€ν•œ 지침 (Guidance for structuring modules)

κ°€λŠ₯ν•œ μ΅œμƒμœ„-λ ˆλ²¨μ— κ°€κΉκ²Œ export ν•˜κΈ° (Export as close to top-level as possible)

λͺ¨λ“ˆμ˜ μ‚¬μš©μžκ°€ export λͺ¨λ“ˆμ„ μ‚¬μš©ν•  λ•Œ κ°€λŠ₯ν•œ 마찰이 적어야 ν•©λ‹ˆλ‹€. 쀑첩 μˆ˜μ€€μ„ κ³Όλ„ν•˜κ²Œ μΆ”κ°€ν•˜λ©΄ 닀루기 νž˜λ“€μ–΄μ§€λŠ” κ²½ν–₯이 μžˆμœΌλ―€λ‘œ, μ–΄λ–»κ²Œ ꡬ쑰λ₯Ό ꡬ성할지 μ‹ μ€‘ν•˜κ²Œ 생각해야 ν•©λ‹ˆλ‹€.

λͺ¨λ“ˆμ—μ„œ λ„€μž„μŠ€νŽ˜μ΄μŠ€λ₯Ό export ν•˜λŠ” 것은 λ„ˆλ¬΄ λ§Žμ€ 쀑첩 λ ˆμ΄μ–΄λ₯Ό μΆ”κ°€ν•˜λŠ” μ˜ˆμž…λ‹ˆλ‹€. λ„€μž„μŠ€νŽ˜μ΄μŠ€λŠ” λ•Œλ•Œλ‘œ μš©λ„κ°€ μžˆμ§€λ§Œ, λͺ¨λ“ˆμ„ μ‚¬μš©ν•  λ•Œ 좔가적인 레벨의 κ°„μ ‘ μ°Έμ‘°λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€. 이것은 μ‚¬μš©μžμ—κ²Œ 금방 κ³ ν†΅μŠ€λŸ¬μš΄ 지점이 될 수 있고, 일반적으둜 λΆˆν•„μš”ν•©λ‹ˆλ‹€.

export ν•œ 클래슀의 정적 λ©”μ„œλ“œμ—λ„ λΉ„μŠ·ν•œ λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€ - 클래슀 μžμ²΄μ— 쀑첩 λ ˆμ΄μ–΄κ°€ μΆ”κ°€λ©λ‹ˆλ‹€. ν‘œν˜„μ΄λ‚˜ μ˜λ„λ₯Ό λͺ…ν™•ν•˜κ²Œ μœ μš©ν•œ λ°©μ‹μœΌλ‘œ 높이지 μ•ŠλŠ” ν•œ κ°„λ‹¨ν•˜κ²Œ 헬퍼 ν•¨μˆ˜λ₯Ό export ν•˜λŠ” 것을 κ³ λ €ν•˜μ„Έμš”.

단일 classλ‚˜ function을 export ν•  경우, export defaultλ₯Ό μ‚¬μš©ν•˜μ„Έμš” (If you're only exporting a single class or function, use export default)

"μ΅œμƒμœ„-λ ˆλ²¨μ— κ°€κΉŒμš΄ export"κ°€ λͺ¨λ“ˆ μ‚¬μš©μžμ˜ λ§ˆμ°°μ„ μ€„μ—¬μ£ΌλŠ” κ²ƒμ²˜λŸΌ, default exportλ₯Ό λ„μž…ν•˜λŠ” 것도 λ§ˆμ°¬κ°€μ§€μž…λ‹ˆλ‹€. λͺ¨λ“ˆμ˜ μ£Όμš” λͺ©μ μ΄ ν•œ 개의 νŠΉμ • exportλ₯Ό μ €μž₯ν•˜λŠ” 것이라면, default export둜 export ν•˜λŠ” 것을 κ³ λ €ν•˜μ„Έμš”. μ΄λ ‡κ²Œ ν•˜λ©΄ import ν•˜κΈ°μ™€ μ‹€μ œλ‘œ importλ₯Ό μ‚¬μš©ν•˜κΈ°κ°€ 더 μ‰¬μ›Œμ§‘λ‹ˆλ‹€. 예λ₯Ό λ“€λ©΄:

MyClass.ts

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

MyFunc.ts

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

Consumer.ts

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

이것은 μ‚¬μš©μžμ—κ²Œ μ΅œμ μž…λ‹ˆλ‹€. νƒ€μž…μ— μ›ν•˜λŠ” 이름(이 κ²½μš°μ—λŠ” t)을 지정할 수 있고 객체λ₯Ό μ°ΎκΈ° μœ„ν•΄ κ³Όλ„ν•œ 점을 찍지 μ•Šμ•„λ„ λ©λ‹ˆλ‹€.

μ—¬λŸ¬ 객체λ₯Ό export ν•˜λŠ” 경우, μ΅œμƒμœ„-λ ˆλ²¨μ— λ‘μ„Έμš” (If you're exporting multiple objects, put them all at top-level)

MyThings.ts

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

λ°˜λŒ€λ‘œ import ν•  λ•Œ:

import ν•œ 이름을 λͺ…μ‹œμ μœΌλ‘œ λ‚˜μ—΄ (Explicitly list imported names)

Consumer.ts

import { SomeType, someFunc } from "./MyThings";
let x = new SomeType();
let y = someFunc();

λ§Žμ€ 것을 import ν•˜λŠ” 경우, λ„€μž„μŠ€νŽ˜μ΄μŠ€ import νŒ¨ν„΄μ„ μ‚¬μš©ν•˜μ„Έμš” (Use the namespace import pattern if you're importing a large number of things)

MyLargeModule.ts

export class Dog { ... }
export class Cat { ... }
export class Tree { ... }
export class Flower { ... }

Consumer.ts

import * as myLargeModule from "./MyLargeModule.ts";
let x = new myLargeModule.Dog();

상속을 μœ„ν•œ re-export ν•˜κΈ° (Re-export to extend)

μ’…μ’… λͺ¨λ“ˆμ˜ κΈ°λŠ₯을 ν™•μž₯ν•΄μ•Ό ν•  ν•„μš”κ°€ μžˆμŠ΅λ‹ˆλ‹€. 일반적인 JS νŒ¨ν„΄μ€ JQuery ν™•μž₯이 μž‘λ™ν•˜λŠ” 방식과 μœ μ‚¬ν•˜κ²Œ *ν™•μž₯(extensions)*으둜 기쑴의 객체λ₯Ό λ³΄κ°•ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. μ•žμ—μ„œ μ–ΈκΈ‰ν–ˆλ“―μ΄ λͺ¨λ“ˆμ€ μ „μ—­ λ„€μž„μŠ€νŽ˜μ΄μŠ€ 객체와 같이 병합(merge) ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ—¬κΈ°μ„œ μΆ”μ²œν•˜λŠ” 방법은 기쑴의 객체λ₯Ό λ³€ν˜•ν•˜μ§€ μ•Šκ³  μƒˆλ‘œμš΄ κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” 개체λ₯Ό export ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

Calculator.ts λͺ¨λ“ˆμ— μ •μ˜λœ κ°„λ‹¨ν•œ 계산기 κ΅¬ν˜„μ„ μƒκ°ν•΄λ³΄μ„Έμš”. 이 λͺ¨λ“ˆλ„ μž…λ ₯ λ¬Έμžμ—΄ λͺ©λ‘μ„ μ „λ‹¬ν•˜κ³  κ²°κ³Όλ₯Ό μž‘μ„±ν•˜μ—¬ κ³„μ‚°κΈ°μ˜ κΈ°λŠ₯을 ν…ŒμŠ€νŠΈν•  수 μžˆλŠ” 헬퍼 ν•¨μˆ˜λ₯Ό export ν•©λ‹ˆλ‹€.

Calculator.ts

export class Calculator {
    private current = 0;
    private memory = 0;
    private operator: string;

    protected processDigit(digit: string, currentValue: number) {
        if (digit >= "0" && digit <= "9") {
            return currentValue * 10 + (digit.charCodeAt(0) - "0".charCodeAt(0));
        }
    }

    protected processOperator(operator: string) {
        if (["+", "-", "*", "/"].indexOf(operator) >= 0) {
            return operator;
        }
    }

    protected evaluateOperator(operator: string, left: number, right: number): number {
        switch (this.operator) {
            case "+": return left + right;
            case "-": return left - right;
            case "*": return left * right;
            case "/": return left / right;
        }
    }

    private evaluate() {
        if (this.operator) {
            this.memory = this.evaluateOperator(this.operator, this.memory, this.current);
        }
        else {
            this.memory = this.current;
        }
        this.current = 0;
    }

    public handleChar(char: string) {
        if (char === "=") {
            this.evaluate();
            return;
        }
        else {
            let value = this.processDigit(char, this.current);
            if (value !== undefined) {
                this.current = value;
                return;
            }
            else {
                let value = this.processOperator(char);
                if (value !== undefined) {
                    this.evaluate();
                    this.operator = value;
                    return;
                }
            }
        }
        throw new Error(`Unsupported input: '${char}'`);
    }

    public getResult() {
        return this.memory;
    }
}

export function test(c: Calculator, input: string) {
    for (let i = 0; i < input.length; i++) {
        c.handleChar(input[i]);
    }

    console.log(`result of '${input}' is '${c.getResult()}'`);
}

λ…ΈμΆœλœ test ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” κ°„λ‹¨ν•œ 계산기 ν…ŒμŠ€νŠΈμž…λ‹ˆλ‹€.

TestCalculator.ts

import { Calculator, test } from "./Calculator";


let c = new Calculator();
test(c, "1+2*33/11="); // 9 좜λ ₯

10이 μ•„λ‹Œ 숫자λ₯Ό μž…λ ₯받을 수 μžˆλ„λ‘ 이것을 μƒμ†ν•˜μ—¬ ProgrammerCalculator.ts을 λ§Œλ“€μ–΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

ProgrammerCalculator.ts

import { Calculator } from "./Calculator";

class ProgrammerCalculator extends Calculator {
    static digits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];

    constructor(public base: number) {
        super();
        const maxBase = ProgrammerCalculator.digits.length;
        if (base <= 0 || base > maxBase) {
            throw new Error(`base has to be within 0 to ${maxBase} inclusive.`);
        }
    }

    protected processDigit(digit: string, currentValue: number) {
        if (ProgrammerCalculator.digits.indexOf(digit) >= 0) {
            return currentValue * this.base + ProgrammerCalculator.digits.indexOf(digit);
        }
    }
}

// μƒˆλ‘œ μƒμ†λœ calculatorλ₯Ό Calculator둜 export ν•˜κΈ°
export { ProgrammerCalculator as Calculator };

// λ˜ν•œ 헬퍼 ν•¨μˆ˜λ„ export ν•˜κΈ°
export { test } from "./Calculator";

μƒˆλ‘œμš΄ ProgrammerCalculator λͺ¨λ“ˆμ€ Calculator λͺ¨λ“ˆκ³Ό μœ μ‚¬ν•œ API ν˜•νƒœλ₯Ό export ν•˜μ§€λ§Œ, μ›λž˜ λͺ¨λ“ˆμ˜ 객체λ₯Ό λ³΄κ°•ν•˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€. λ‹€μŒμ€ ProgrammerCalculator ν΄λž˜μŠ€μ— λŒ€ν•œ ν…ŒμŠ€νŠΈμž…λ‹ˆλ‹€:

TestProgrammerCalculator.ts

import { Calculator, test } from "./ProgrammerCalculator";

let c = new Calculator(2);
test(c, "001+010="); // 3 좜λ ₯

λͺ¨λ“ˆμ—μ„œ λ„€μž„μŠ€νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜μ§€ λ§ˆμ„Έμš” (Do not use namespaces in modules)

λͺ¨λ“ˆ 기반 ꡬ성을 처음 μ μš©ν•  λ•Œ, 일반적으둜 좔가적인 λ„€μž„μŠ€νŽ˜μ΄μŠ€ κ³„μΈ΅μ—μ„œ exportsλ₯Ό λž˜ν•‘ ν•˜λŠ” κ²½ν–₯이 μžˆμŠ΅λ‹ˆλ‹€. λͺ¨λ“ˆμ—λŠ” 자체 μŠ€μ½”ν”„κ°€ 있으며, export된 μ„ μ–Έλ§Œ λͺ¨λ“ˆ μ™ΈλΆ€μ—μ„œ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό 염두에 두고 λ„€μž„μŠ€νŽ˜μ΄μŠ€λŠ” λͺ¨λ“ˆμ„ λ‹€λ£° λ•Œ 거의 값을 λ³€κ²½ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

ꡬ성 μ „λ©΄μ—μ„œ λ„€μž„μŠ€νŽ˜μ΄μŠ€λŠ” λ…Όλ¦¬μ μœΌλ‘œ κ΄€λ ¨λœ κ°œμ²΄μ™€ νƒ€μž…μ„ μ „μ—­ μŠ€μ½”ν”„λ‘œ κ·Έλ£Ήν™”ν•˜λŠ”λ° νŽΈλ¦¬ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, C#의 경우, System.Collectionsμ—μ„œ λͺ¨λ“  μ»¬λ ‰μ…˜ νƒ€μž…μ„ 찾을 수 μžˆμŠ΅λ‹ˆλ‹€. νƒ€μž…μ„ 계측적 λ„€μž„μŠ€νŽ˜μ΄μŠ€λ‘œ κ΅¬μ„±ν•˜μ—¬ ν•΄λ‹Ή νƒ€μž…μ˜ μ‚¬μš©μžμ—κ²Œ "발견"ν•  수 μžˆλŠ” 쒋은 κ²½ν—˜μ„ μ œκ³΅ν•©λ‹ˆλ‹€. 반면, λͺ¨λ“ˆμ€ 이미 파일 μ‹œμŠ€ν…œμ— λ°˜λ“œμ‹œ μ‘΄μž¬ν•©λ‹ˆλ‹€. κ²½λ‘œμ™€ 파일 μ΄λ¦„μœΌλ‘œ ν•΄μ„ν•˜κΈ° μœ„ν•΄μ„œ, 논리적 ꡬ성 체계λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 리슀트 λͺ¨λ“ˆμ΄ μžˆλŠ” /collections/generic/ 폴더λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ„€μž„μŠ€νŽ˜μ΄μŠ€λŠ” μ „μ—­ μŠ€μ½”ν”„μ—μ„œ 넀이밍 μΆ©λŒμ„ ν”Όν•˜κΈ° μœ„ν•΄ μ€‘μš”ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, My.Application.Customer.AddFormκ³Ό My.Application.Order.AddForm -- 두 νƒ€μž…μ˜ 이름은 κ°™μ§€λ§Œ λ‹€λ₯Έ λ„€μž„μŠ€νŽ˜μ΄μŠ€λ₯Ό 가지고 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 이것은 λͺ¨λ“ˆμ—μ„œ λ¬Έμ œκ°€ λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λͺ¨λ“ˆ λ‚΄μ—μ„œ 두 개의 객체가 같은 이름을 κ°€μ§ˆλ§Œν•œ μ΄μœ λŠ” μ—†μŠ΅λ‹ˆλ‹€. μ‚¬μš© μΈ‘λ©΄μ—μ„œ νŠΉμ • λͺ¨λ“ˆμ˜ μ‚¬μš©μžλŠ” λͺ¨λ“ˆμ„ μ°Έμ‘°ν•˜λŠ”λ° μ‚¬μš©ν•  이름을 μ„ νƒν•˜λ―€λ‘œ μš°μ—°ν•œ 이름 μΆ©λŒμ€ λΆˆκ°€λŠ₯ν•©λ‹ˆλ‹€.

λͺ¨λ“ˆκ³Ό λ„€μž„μŠ€νŽ˜μ΄μŠ€μ— λŒ€ν•œ μžμ„Έν•œ λ‚΄μš©μ€ Namespaces and Modulesλ₯Ό μ°Έκ³ ν•˜μ„Έμš”

μœ„ν—˜ μ‹ ν˜Έ (Red Flags)

λ‹€μŒμ€ λͺ¨λ‘ λͺ¨λ“ˆ ꡬ쑰화에 λŒ€ν•œ μœ„ν—˜ μ‹ ν˜Έμž…λ‹ˆλ‹€. λ‹€μŒ 쀑 ν•˜λ‚˜λΌλ„ νŒŒμΌμ— μ μš©λ˜λŠ” 경우 μ™ΈλΆ€ λͺ¨λ“ˆμ˜ λ„€μž„μŠ€νŽ˜μ΄μŠ€λ₯Ό λ§Œλ“€λ €κ³  ν•˜μ§€ μ•Šμ•˜λŠ”μ§€ λ‹€μ‹œ ν™•μΈν•˜μ„Έμš”:

  • 였직 μ΅œμƒμœ„-레벨 μ„ μ–Έλ§Œ export namespace Foo { ... }인 파일 (Fooλ₯Ό μ œκ±°ν•˜κ³  λͺ¨λ“  것을 'μƒμœ„' 레벨둜 μ΄λ™ν•˜μ„Έμš”)
  • μ΅œμƒμœ„-레벨 μœ„μΉ˜μ— λ™μΌν•œ export namespace Foo {λ₯Ό 가진 μ—¬λŸ¬ 파일 (ν•˜λ‚˜μ˜ Foo둜 결합될 거라 μƒκ°ν•˜μ§€ λ§ˆμ„Έμš”!)