TYPESCRIPT #2 타입스크립트 프로젝트 생성과 관리

soohee·2021년 8월 6일
0

TYPESCRIPT

목록 보기
1/1

🐙 02-1 타입스크립트 프로젝트 만들기

package.json은 npm init을 통해 생성한다.

package.json은 node.js가 관리하는 패키지 관리 파일로서 프로젝트 정보와 관련 패키지가 기록된다.

🦑 프로젝트 생성자 관점에서 패키지 설치하기

다양한 오픈소스 패키지를 npm install 혹은 npm i 로 설치한다.

이 옵션으로 설치하면, 해당 패키지 정보가 package.json 파일에 자동으로 기록된다.

-g 옵션으로 설치하면 전역에 설치할 수 있다.

그러나, 이 프로젝트를 전달받아서 사용하는 다른 개발자의 컴퓨터에는 두 패키지가 전역에 설치되지 않았을 수도 있다.

따라서, - D 옵션을 이용해서 설치하는 것이 좋다.

npm i -D typescript ts-node

타입스크립트의 컴파일러는 자바스크립트와 달리, 타입이 명시적으로 설정되어 있어야만 코드가 문법에 맞게 작성되었는지를 검증해 코드를 동작시킨다.

이 때문에, 자바스크립트로 개발된 chance와 ramda와 같은 라이브러리들은 추가로 @types/chance, @types/ramda 와 같은 타입 라이브러리들을 제공해야 한다.

🦐 프로젝트 이용자 관점에서 패키지 설치하기

프로젝트를 만드는 과정에서 패키지를 설치하면, 자연스럽게 프로젝트 디렉터리 아래에 node_modules라는 디렉터리가 생기고, 여기에 해당 패키지가 설치된다.

그러나, 여러 패키지를 설치하다보면 node_modules의 용량이 늘어난다.

이때, node_modules을 삭제하고 다른 사람에게 전달하면, 프로젝트 이용자는 package.json파일이 있는 디렉터리에서 npm i 를 실행하면 package.json에 등록된 패키지들이 node_modules디렉토리에 자동으로 설치된다.

🐠 tsconfig.json 파일 만들기

tsconfig.json는 타입스크립트 컴파일러 설정 파일이다. 이 파일은 tsc —init명령으로 만들수 있다.

기본적으로 이 파일에는 실제 개발을 진행하는 데 필요한 많은 옵션이 비활성화 되어있다.

따라서, 옵션을 알맞게 설정하여 간략하게 하자.

이 책에서는 이렇게 되어있다.

// tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs",
    "esModuleInterop": true,
    "target": "es2015",      
    "moduleResolution": "node",      
    "outDir": "dist",
    "baseUrl": ".",
    "sourceMap": true,
    "downlevelIteration": true,
    "noImplicitAny": false,
    "paths": { "*": ["node_modules/*"] }
  },
  "include": ["src/**/*"]
}

🦀 src 디렉토리와 소스 파일 만들기

tsconfig.json에서 14행인 "include": ["src/*/"] 는 ./src 와 ./src/utils 디렉토리에 이 프로젝트의 모든 타입스크립트 소스 파일이 있다는 뜻이다.

src/utils 디렉토리르 만들고 실습에 필요한 소스 파일을 만들자.

mkdir -p src/utils
touch src/index.ts src/utils/makePerson.ts
// src/utils/makePerson.ts
export function makePerson(name:string, age: number){
    return {name:name, age:age}
}
export function testMakePerson(){
    console.log(
        makePerson('Jane', 22),
        makePerson('Jack', 33)
    )
}
// src/index.ts
import { testMakePerson  } from "./utils/makePerson"
testMakePerson()

🐾 시작 소스 파일명을 index로 짓는 이유

node 나 ts-node로 소스파일을 실행하려면 ts-node ./src/index.ts 명령을 사용한다.

하지만, 소스파일명이 index면 ts-node ./src로 실행할 수 있다.

이는 프로젝트 시작 함수 (엔트리 함수)가 있는 소스 파일명은 보통 index라고 짓기 떄문이다.

🦞 package.json 수정

타입스크립트 프로젝트를 개발할 때는 ts-node를 사용하지만, 막상 개발이 완료되면 타입스크립트 소스코드를 ES5 자바스크립트 코드로 변환해 node로 실행해야한다.

그러기 위해서 다음과 같은 명령을 추가해준다.

{
  "name": "ch02-1",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    **"dev": "ts-node src",
    "build": "tsc && node dist"**
  },
... 생략 ...

dev는 index.ts를 실행하기 위해서, 그리고 build는 개발이 완료된 후 프로그램을 배포하기 위해 dist 디렉토리에 ES5 자바스크립트 파일을 만들 떄 사용한다.

이 명령들은 다음과 같이 실행한다.

npm run 명령
// npm run dev
// npm run build

🐬 02-2 모듈 이해하기

타입스크립트에서 index.ts와 같은 소스파일을 모듈이라고 한다.

여러 모듈을 하나의 파일로 합쳐도 되지만, 보통 코드 관리와 유지, 보수를 편리하게 하려고 모듈마다 고유한 기능을 구현하는 방식으로 소스코드를 분할한다. ( 모듈화 )

이때, 어떤 모듈이 어디있는지를 알려주기 위해, export 와 import를 사용한다.

export는 기능을 제공하는 쪽에서 사용하고, import는 딴 모듈의 기능을 이용하는 쪽에서 사용한다.

🐳 index.ts 파일의 모듈화

index.ts 파일을 모듈화 하기 위해 src 디렉토리 아래에 person 디렉토리를 생성 후 Person.ts라는 이름의 파일을 만든다.

// src/person/Person.ts
class Person implements IPerson {
  constructor(public name: string, public age: number = makeRandomNumber()) {}
}

const makePerson = (name: string, 
                          age:number = makeRandomNumber()): IPerson => ({name, age});

이렇게 되면 index.ts 파일이 간단해진다.

// index.ts
const testMakePerson = (): void => {
  let jane: **IPerson** = **makePerson**("Jane");
  let jack: **IPerson** = new Person("Jack");
  console.log(jane, jack);
}
testMakePerson();

그러나 여기서 오류가 발생한다.

IPerson과 makePerson이라는 심벌의 의미를 알 수 없기 때문이다.

여기서, export와 import가 필요한 것이다.

🐋 export 키워드

index.ts파일이 동작하려면, Person.ts 파일에 선언한 IPerson과 makePerson심벌을 index.ts로 전해야 한다. 이때, export 키워드가 쓰인다.

// src/person/Person.ts
**export default** class Person implements IPerson {
  constructor(public name: string, public age: number = makeRandomNumber()) {}
}

**export** const makePerson = (name: string, 
                          age:number = makeRandomNumber()): IPerson => ({name, age});

🐟 import 키워드

import 키워드는 아래처럼 쓰인다.

import { 심벌 목록 } from '파일의 상대 경로'

index.ts 파일을 열고 다음처럼 첫 줄에 import 구문을 추가한다.

// src/index.ts
import IPerson from './person/IPerson'
import Person, {makePerson} from './person/Person'

const testMakePerson = (): void => {
  let jane: IPerson = makePerson("Jane");
  let jack: IPerson = new Person("Jack");
  console.log(jane, jack);
}
testMakePerson();

🦠 import * as 구문

심벌을 사용하는 방법도 존재한다.

import * as 심벌 from '파일 상대 경로'

이런식으로 사용한다.

// src/person/Person.ts
import * as U from '../utils/makeRandomNumber'
import IPerson from './IPerson'

export default class Person implements IPerson {
  constructor(public name: string, public age: number = **U.makeRandomNumber()**) {}
}

export const makePerson = (name: string, 
                          age:number = **U.makeRandomNumber()**): IPerson => ({name, age});

🦄 export default 키워드

타입스크립트는 자바스크립트와 호환하기 위해 export default 구문을 제공한다.

// src/person/IPerson.ts
export default interface IPerson {
  name: string,
  age: number
}

export default 키워드는 한 모듈이 내보내는 기능 중 오직 한 개만 붙일 수 있다.

export default가 붙은 기능은 import문으로 불러올 떄 중괄호 {} 없이 사용할 수 있다.

이제, Person.ts를 다음과 같이 수정하자.

// src/person/Person.ts
import {makeRandomNumber} from '../utils/makeRandomNumber'
import IPerson from './IPerson'

export default class Person implements IPerson {
  constructor(public name: string, public age: number = makeRandomNumber()) {}
}

export const makePerson = (name: string, 
                          age:number = makeRandomNumber()): IPerson => ({name, age});

2행은 IPerson.ts에서 export default 키워드로 지정한 IPerson을 중괄호 없이 import문에 지정했다.

지금까지의 내용을 모두 반영한 index.ts모습은 이렇다.

// src/index.ts
import IPerson from './person/IPerson'
import Person, {makePerson} from './person/Person'

const testMakePerson = (): void => {
  let jane: IPerson = makePerson("Jane");
  let jack: IPerson = new Person("Jack");
  console.log(jane, jack);
}
testMakePerson();

👘 외부 패키지를 사용할 때 import 문

실습을 위해 chance와 ramda 패키지를 설치하자.

npm i -S chance ramda
npm i -D @types/chance @types/ramda

chance패키지는 그럴듯한 가짜 데이터를 만들어 주는데 사용되며, ramda는 함수형 유틸리티 패키지 이다.

이 패키지를 이용하면 index.ts는 다음과 같이 바뀐다.

// src/index.ts
import IPerson from './person/IPerson'
import Person from './person/Person'
import Chance from 'chance'
import * as R from 'ramda'

const chance = new Chance()
let persons: IPerson[] = R.range(0, 2).map(
  (n: number) => new Person(chance.name(), chance.age())
)
console.log(persons)

chance는 Chance 클래스 하나만 export default 형태로 제공하므로 03행 같이 쓰인다.

그리고 ramda패키지는 다양한 기능을 제공하므로 04행 처럼 쓰인다.

🐛 02-3 tsconfig.json 파일 살펴보기

!!!!!!!!!!!!!!!!!!!!!!1 tsc — help 해볼것

앞에서 만든 tsconfig.json파일은 다음처럼 되어있다.

{
  "compilerOptions": {
    "module": "commonjs",
    "esModuleInterop": true,
    "target": "es2015",      
    "moduleResolution": "node",      
    "outDir": "dist",
    "baseUrl": ".",
    "sourceMap": true,
    "downlevelIteration": true,
    "noImplicitAny": false,
    "paths": { "*": ["node_modules/*"] }
  },
  "include": ["src/**/*"]
}

compilerOptions항목은 tsc 명령 형시겡서 옵션을 나타내고, include 항목은 대상 파일 목록을 나타낸다.

src/*/ 은 src 디렉토리는 물론 src의 하위 디렉토리에 있는 모든 파일을 컴파일 대상으로 포함한다는 의미다.

각각 콜론을 기준으로 "키 : 키값"으로 되어있다.

🐲 module 키

타입스크립트 소스코드가 컴파일 되어 만들어진 ES5 자바스크립트 코드는 웹 브라우저와 노드제이에스 양쪽에서 모두 동작해야한다.

그러나, 둘은 물리적인 동작방식이 달라서 모듈로 분할된 자바스크립트 코드도 양쪽에서 다르게 동작한다.

자바스크립트 모듈은 웹 브라우저에서 AMD방식으로, 노드제이에스처럼 웹 브라우저가 아닌 환경에서는 CommonJS방식으로 동작한다.

tsconfig.ts 파일에서동작 대상 플랫폼을 구분해 그에 맞는 모듈 방식으로 컴파일하려는 목적을 설정한다.

  • 웹 브라우저에서 동작 : amd
  • 노드제이에스에서 동작 : commonJS

👽 moduleResolution 키

module 키의 값이 commonJS면 노드제이에스에서 동작하는 것이므로, modeResolution키값은 항상 node로 설정핟나. 반면 module 키값이 amd 이면 moduleResolution키 값은 classic으로 설정한다.

🐸 target 키

트랜스파일할 대상 자바스크립트 버전을 설정한다. 대부분 es5를 키값으로 하나, 최신 버전 노드제이에스를 쓴다면 es6으로 할 수도 있다.

🦎 baseUrl과 outDir키

baseUrl과 outDir키에는 트랜스 파일된 ES5 자바스크립트 파일을 저장하는 디렉터리를 설정한다. 그래서, 현재 디렉터리를 의미하는 ".'로 baseUrl키값을 설정하는게 보통이다. OutDir키는 baseUrl설정값을 기준으로 했을 때 하위 디렉터리의 이름이다.

🐊 paths 키

이 키에는 소스파일의 import 문에서 from 부분을 해석할 때 찾아야하는 디레거리를 설정한다.

import 문이 찾아야하는 소스가 외부 패키지면 node_modules 디렉토리에서 찾아야 하므로, node_modules/* 도 포함한다.

🐢 esModuleInterop키

오픈소스 자바스크립트 라이브러리 중에는 웹 브라우저에서 동작한다는 가정으로 만들어 진것들이 있다. 이들은 CommonJS방식으로 동작하는 타입스크립트 코드에 혼란을 줄 수 있다.

예를 들어, 02-2에서 chance가 바로 AMD방식을 전제로 해서 구현된 라이브러리이다.

따라서, chance를 실행하기 위해서는 esModuleInterop키 값을 반드시 true로 설정해야 한다.

🐍 sourceMap키

sourceMap키 값이 true면 트랜스파일 디렉터리에는 .js파일 이외에도 .js.map 파일이 만들어진다.

이 소스맵 파일은 변환된 자바스크립트 코드가 타입스크립트 코드의 어디에 해당하는지 알려준다.

이 소스맵 파일은 주로 디버깅 할 때 사용된다.

🦗 downlevelIteration키

이 책의 06장에서는 생성기 라는 타입스크립트 구문을 설명하는데, 이 생성기 구문이 정상적으로 동작하려면, downlevelIteration키가 true로 되어있어야한다.

🦚 noImplicitAny키

타입스크립트의 컴파일러는 기본적으로 f(a, b)처럼 매개변수 a,b에 타입을 명시하지 않는경우 자동으로 any타입으로 설정한다. 이런 코드는 타입스크립트를 사용하는 의미를 퇴색시키므로, 이런 코드가 있을 때 문제가 있음을 알려준다.

profile
🐻‍❄️

0개의 댓글