TypeScript는 export나 최상위 await가 없는 JavaScript 파일을 모듈이 아닌 스크립트로 간주한다고 선언합니다.
또한 스크립트 안에서 작업할 때 변수와 타입은 공유 전역 스코프 내부에 있다고 선언됩니다.
모든 코드가 한 전역 스코프(global scope)에 있다고 간주한다는 의미입니다.
//utils.ts
function add(x: number, y: number) {
return x + y;
}
function sample<T>(arr: T[]): T {
const idx = Math.floor(Math.random() * arr.length);
return arr[idx];
}
const x = 1;
다른 파일에 작성된 코드이지만 함수를 부를 때 문제가 생기지 않습니다.
하지만 const를 두 번 선언하자 문제가 발생합니다.
// index.ts
add(1, 2)
sample([12, 3, 34])
// Cannot redeclare block-scoped variable 'x'
const x = 2
모든 코드가 같은 스코프에 있는 것은 변수를 선언할 때 다른 파일에서 정의한 이름과 같거나 다른 파일과 같은 이름의 함수를 정의하는 것은 자주 일어날 수 있으며, 이는 문제가 될 수 있습니다.
TypeScript는 export 키워드를 넣어 두는 순간 모듈(module)에서 작업한다고 인식하기 시작합니다.
//utils.ts
export function add(x: number, y: number) {
return x + y;
}
export function sample<T>(arr: T[]): T {
const idx = Math.floor(Math.random() * arr.length);
return arr[idx];
}
// index.ts
// Cannot find name 'add'
add(1, 2)
// Cannot find name 'sample'
sample([12, 3, 34])
export를 사용하면 각 파일이 각자 독립된 파일과 네임스페이스로 분리되어, 공유하려는 함수 기능을 일일이 가져오고 내보내야 합니다.
import할 때 유의 해야할 사항은 파일명이 .ts가 아니라 .js로 해야합니다.
//utils.ts
export function add(x: number, y: number) {
return x + y;
}
export function sample<T>(arr: T[]): T {
const idx = Math.floor(Math.random() * arr.length);
return arr[idx];
}
// index.ts
import { add, sample } from "./utils.js";
add(1, 2)
sample([12, 3, 34])
export 키워드를 사용한 TypeScript는 CommonJS로 컴파일링 합니다.
하지만 브라우저 내 JavaScript는 CommonJS 모듈을 이해하지 못해서 exports 키워드가 무엇인지도 모르고 모듈도, require 키워드도 이해하지 못합니다.
따라서 tsconfig.json파일에서 import와 export가 있는 ES Module을 사용하도록 설정을 해야 합니다.
// tsconfig.json
{
"compilerOptions": {
"module": "ES6"
}
}
index.html의 type도 module로 바꾸어 줍니다.
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Modules</title>
</head>
<body>
<script type="module" src="./dist/index.js"></script>
</body>
</html>
TypeScript에서는 파일끼리 타입을 공유할 수 있습니다.
컴파일링된 JavaScript에서 import type은 사라집니다.
// types.ts
export interface Person {
username: string;
email: string;
}
export type Color = "red" | "green" | "blue";
// User.ts
//(alias) interface Person
import type { Person } from "./types.js";
export default class User implements Person {
constructor(public username: string, public email: string) {}
logout() {
console.log(`${this.username} logs out`);
}
}
export function userHelper() {
console.log("USER HELPER!");
}
아래와 같이 작성하면 타입이 아닌 모듈과 함께 사용할 수 있습니다.
import { type Person, 타입이아닌다른모듈 } from "./types.js";
export default class User implements Person {
constructor(public username: string, public email: string) {}
logout() {
console.log(`${this.username} logs out`);
}
}
export function userHelper() {
console.log("USER HELPER!");
}