6 분 소요


1. 컴파일러와 TSC

1.1 컴파일러의 개념

  • 컴파일러란 프로그래밍 언어로 작성된 소스 코드 → 다른 프로그래밍 언어로 변환하는 도구이다.
  • 변환 과정에서 컴파일러는 소스 코드의 구문과 구조를 검사하여 문제가 없는지 확인한다.


1.2 컴파일러의 역할

1️⃣ 타입 검사를 해준다.

TS 컴파일러인 TSC는 소스 코드의 정적 타입 검사를 수행하여 개발자가 코드에서 타입 관련 오류를 미리 발견하고 수정할 수 있게 한다.


2️⃣ 코드 변환을 해준다.

C언어 컴파일러가 C언어에서 기계어로 코드 변환을 해주는 것처럼, 타입스크립트 컴파일러인 TSC는 TypeScript → JavaScript 코드 변환을 해준다.


3️⃣ 자동으로 최적화를 해준다.

코드가 최적화되면 전반적인 어플리케이션 실행 시간이 더 빨라진다.


1.3 동적 언어 JS

JavaScript는 동적 언어(=인터프리터 언어)이기 때문에 기계어로 변환될 필요가 없다.

  • Node.js나 Chrome → JavaScript를 실행할 때는 V8 엔진이 코드 해석 및 실행을 한다.
  • Firefox → JavaScript를 실행할 때는 SpiderMonkey가 코드 해석 및 실행을 한다.


정리하면, 정적 언어(=컴파일 언어)는 기계어로 변환이 되어야 하지만, 동적 언어(=인터프리터 언어)는 엔진이 코드를 한 줄씩 실행하면서 동적으로 해석한다.


1.4 TSC 명령어

자세한 명령어 옵션 확인하기 : tsc CLI Options


  • tsc —-init
    • tsconfig.json이 생성되는 명령어이다.
  • tsc index.ts
    • index.ts를 컴파일 한다.
    • .tsTypeScript 파일의 확장자이다.
  • tsc src/*.ts
    • src 디렉토리 안에 있는 모든 TypeScript 파일을 컴파일한다.
  • tsc index.js --declaration --emitDeclarationOnly
    • @types 패키지를 위한 .d.ts 파일 생성을 하는 명령이다.
    • TypeScript로 작성된 모듈이 아니라 JavaScript로 작성된 모듈에 타입 선언을 제공할 때 유용하게 쓰인다.



2. tsconfig.json 개요

2.1 tsconfig.json 개념

  • TS 프로젝트의 설정 파일이다.
  • 주로 프로젝트의 컴파일 옵션 및 입력 파일들을 정의하는데 사용된다.
  • tsc --init 명령을 실행하면 생성되는 파일이다.


2.2 tsconfig.json 주요 옵션

옵션 매뉴얼 : https://www.typescriptlang.org/ko/tsconfig

주요 옵션에 살펴보기에 앞서, 아래 설정을 마치도록 하자.

  • compilerOptions - strict옵션은 true로 설정하기
  • compilerOptions - sourceMap옵션은 개발 환경에서 true로 설정하기


2.2.1 compilerOptions - target 옵션

  • 해당 TypeScript 프로젝트 내 코드들이 어떤 JavaScript 버전으로 변환을 할 지 정하는 옵션이다.
  • es5 로 설정하면 CommonJS 버전으로 컴파일이 되며, es2016(=es7) 로 설정하면 ES2016 버전으로 컴파일이 된다.


2.2.2  compilerOptions - module 옵션

  • TypeScript 파일을 컴파일한 후 생성되는 JavaScript 모듈의 형식을 지정한다.
  • 모듈을 가져오고 내보내는 방식을 결정하는 옵션이다.
  • target 옵션과는 서로 독립적인 관계니 프로젝트의 요구사항에 따라 옵션을 설정하면 된다.


2.2.3 compilerOptions 옵션

compilerOptions - outDir 옵션

  • 컴파일된 JavaScript 파일이 저장될 출력 디렉터리를 지정한다.
  • 예를 들어, "outDir": "dist"로 설정하면 컴파일된 파일들이 dist 폴더에 저장된다.


compilerOptions - strict 옵션

  • 엄격한 타입 검사 옵션을 모두 활성화하는 옵션이다.
  • TypeScript 컴파일러가 보다 엄격한 타입 검사를 수행해 코드의 실수를 미리 찾아낼 수 있다.


2.2.4 compilerOptions - sourceMap 옵션

  • 컴파일된 JavaScript 파일에 대한 소스 맵을 생성하는 옵션이다.
  • 소스 맵을 사용하면 실행 중에 에러가 발생했을 때 원래 TypeScript 소스 코드의 위치를 확인할 수 있다.
  • 코드 디버깅에 매우 큰 도움이 되기 때문에 개발 환경에서는 true로 설정하는게 좋다.
  • 프로덕션 환경에서는 용량이나 성능상의 이유로 sourceMap을 사용하지 않는 것이 나을 수 있다.


2.2.5 include , exclude 옵션

  • tsc가 컴파일을 할 때 포함하거나 제외할 파일이나 디렉터리를 지정하는 옵션이다.
  • “include”: [“src/*/”]
    • src 디렉토리 밑의 친구들을 컴파일 하겠다는 의미이다.
  • “exclude”: [“node_modules”, “dist”]
    • node_modules, dist 디렉토리 밑의 친구들은 컴파일 대상에서 제외하겠다는 의미이다.



3. .d.ts 파일 개요

3.1 .d.ts 파일 개념

d.ts 파일을 통해서 js 파일의 타입으로 인식울 할 수 있다.

  • TypeScript 타입 정의 파일이다.
  • JavaScript 라이브러리에 대한 타입 정보를 제공하며 타입 추론도 가능하다.
  • JavaScript 라이브러리를 TypeScript에서 쓰려면 해당 라이브러리에 대한 .d.ts 파일만 제공을 해주면 된다. (한 줄도 수정하지 않고 그대로 사용 가능)


3.2 JS 라이브러리를 TS 프로젝트에서 사용하기

① 아래의 명령어를 터미널에서 실행하자

npm init -y


② 다음으로 tsconfig.json을 생성하여 TypeScript 프로젝트로 변환하면 된다.

tsc --init


③ tsconfig.json을 열어서 아래의 옵션을 주석 해제하여 true로 설정하자

"allowJs": true // TypeScript 프로젝트에 JavaScript 파일 허용 여부
"checkJs": true // JavaScript 파일 타입 체크 여부


④ 그 후, TypeScript에서 사용하고 싶은 커스텀 JavaScript 라이브러리(test.js)를 만들면 된다.

/**
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */
export function add(a, b) {
  return a + b;
}

주석으로 매개변수 a와 b의 타입이 숫자이며, 함수의 반환 값의 타입이 숫자임을 명시하고 있다.

  1. 위의 주석문은 JSDoc이라고 한다.
  2. JSDoc은 API의 시그니처 (인자, 리턴 타입)를 설명하는 HTML 문서 생성기이다.
  3. JSDoc으로 자바스크립트 소스코드에 타입 힌트를 제공할 수 있다.



⑤ 이제, JSDoc으로 타입 힌트가 제공된 test.js의 .d.ts 파일을 만들자.

아래의 명령어를 복사 + 붙여넣기를 해서 터미널에서 실행하자.

npx tsc test.js --declaration --allowJs --emitDeclarationOnly --outDir types


⑥ types/test.d.ts 파일을 확인하면 다음과 같이 생성이 되어있다.

/**
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */
export function add(a: number, b: number): number;


⑦ test.js 파일을 참조할 foo.ts 파일을 새로 만들어보자

import { add } from "./test";
console.log(add(1, 2));


⑧ 이제 foo.ts 파일을 실행시켜 보자

실행하면 3이라는 숫자가 뜨며 정상적으로 실행이 됨을 확인 할 수 있다.

npx ts-node foo.ts



4. 실습-성적표 프로그램 만들기

4.1 프로젝트 세팅

① 프로그램이 위치할 프로젝트 디렉토리를 새로 만들자

터미널로 만들 경우 아래처럼!

mkdir first
cd first


② 그 후, 해당 디렉토리에서 아래 명령어를 실행하자

npm init -y
tsc --init --rootDir ./src --outDir ./dist --esModuleInterop --module commonjs --strict true --allowJS true --checkJS true
  • --rootDir ./src
    • 프로그램의 소스 파일이 들어가는 경로는 src 디렉토리.
  • --outDir ./dist
    • 컴파일이 된 파일들이 들어가는 디렉토리는 dist 디렉토리.
  • --esModuleInterop
    • CommonJS 방식의 모듈을 ES모듈 방식의 import 구문으로 가져올 수 있다.


③ package.json의 “scripts” 항목을 아래와 같이 변경하자

"scripts": {
    "start": "tsc && node ./dist/index.js",
    "build": "tsc --build",
    "clean": "tsc --build --clean"
},


④ 이제 src 디렉토리도 생성하자.


⑤ 마지막으로, 해당 디렉토리 위치를 기반으로 편집기를 열어서 코딩 준비를 하자

code .


4.2 구현하고자 하는 기능

  • 학생 정보 및 시험 점수 입력 기능
  • 평균 점수 및 학점 계산 기능


4.3 구현하기

src 디렉토리 안에 index.ts라는 파일을 만들고 아래와 같은 함수를 만들려고 한다.

function assignGrade(average: number): string { ... }
  • 이 함수는 평균 점수에 따라서 학점을 부여하는 함수이다.
  • 평균이 90점 이상이면 “A”, 80점 이상이면 “B”, 70점 이상이면 “C”, 60점 이상이면 “D”, 그 이하면 “F”를 준다.


한 번 스스로 작성해보자!

function assignGrade(average: number): string {
  if (average >= 90) {
    return "A";
  } else if (average >= 80) {
    return "B";
  } else if (average >= 70) {
    return "C";
  } else if (average >= 60) {
    return "D";
  } else {
    return "F";
  }
}



다음으로 학생이 가져야 될 속성들을 정의해서 객체로 만들어보자.
interface는 객체의 구조를 정의하는 방법이다.
객체가 특정 인터페이스를 구현하려면 인터페이스에 정의된 모든 속성을 가져야 한다.

interface Student {
  name: string;
  age: number;
  scores: {
    korean: number,
    math: number,
    society: number,
    science: number,
    english: number,
  };
}



Student라는 타입의 객체를 받아서 평균을 계산하는 calculateAverage라는 함수를 만들어보자.

function calculateAverage(student: Student): number { ... }


한 번 스스로 작성해보자.

function calculateAverage(student: Student): number {
  const sum =
    student.scores.korean +
    student.scores.math +
    student.scores.society +
    student.scores.science +
    student.scores.english;
  const average = sum / 5;
  return average;
}


Object.keys() 함수를 이용하면 특정 속성을 이루는 키 값들을 배열로 반환하기 때문에 average 값을 구할 때 student의 scores 속성에 과목이 추가되거나 삭제되면 나누는 숫자를 우리가 매번 바꿀 필요가 없다!

function calculateAverage(student: Student): number {
  const sum =
    student.scores.korean +
    student.scores.math +
    student.scores.society +
    student.scores.science +
    student.scores.english;
  const average = sum / Object.keys(student.scores).length;
  return average;
}


Student를 생성하는 함수를 만들어보자

function createStudent(
  name: string,
  age: number,
  korean: number,
  math: number,
  society: number,
  science: number,
  english: number
): Student {
  return {
    name,
    age,
    scores: {
      korean,
      math,
      society,
      science,
      english,
    },
  };
}


성적을 출력하는 함수도 만들어보자

function printResult(student: Student): void {
  const average = calculateAverage(student);
  const grade = assignGrade(average);
  console.log(
    `${student.name} (${student.age}세) - 평균: ${average.toFixed(
      2
    )}, 학점: ${grade}`
  );
}


메인 함수를 만들어보자

function main(): void {
  const sieun = createStudent("sieun", 22, 95, 89, 76, 90, 97);
  printResult(sieun);
}


지금까지 작성한 index.ts 코드는 다음과 같다.

interface Student {
  name: string;
  age: number;
  scores: {
    korean: number,
    math: number,
    society: number,
    science: number,
    english: number,
  };
}

function createStudent(
  name: string,
  age: number,
  korean: number,
  math: number,
  society: number,
  science: number,
  english: number
): Student {
  return {
    name,
    age,
    scores: {
      korean,
      math,
      society,
      science,
      english,
    },
  };
}

function calculateAverage(student: Student): number {
  const sum =
    student.scores.korean +
    student.scores.math +
    student.scores.society +
    student.scores.science +
    student.scores.english;
  const average = sum / 5;
  return average;
}

function assignGrade(average: number): string {
  if (average >= 90) {
    return "A";
  } else if (average >= 80) {
    return "B";
  } else if (average >= 70) {
    return "C";
  } else if (average >= 60) {
    return "D";
  } else {
    return "F";
  }
}

function printResult(student: Student): void {
  const average = calculateAverage(student);
  const grade = assignGrade(average);
  console.log(
    `${student.name} (${student.age}세) - 평균: ${average.toFixed(
      2
    )}, 학점: ${grade}`
  );
}

function main(): void {
  const sieun = createStudent("sieun", 22, 95, 89, 76, 90, 97);
  printResult(sieun);
}

main();


이제, 실행을 해보자! index.ts 파일이 반드시 src 디렉토리 밑에 있어야 한다.

해당 명령어로 프로젝트를 빌드한다.

npm run build


컴파일이 완료되면 프로젝트 디렉토리에서 아래 명령어를터미널에서 실행하자.

npm run start


아래처럼 출력이 되면 성적표 프로그램을 성공적으로 만든 것이다!

sieun (22) - 평균: 89.40, 학점: B


댓글남기기