프로젝트에 백엔드 언어로 TypeScript
이용을 결정하고, 프로젝트 초기 설정을 하는 과정 중 바로 문제에 직면했다. TypeScript
가 Compile 하는 도구만 설치한다고 바로 프로젝트에 TypeScript
가 적용되는 것이 아니었다. 어떤 것을 검사할 지에 대한 설정을 하는 작업이 필요했다. 하지만 아무것도 모른채로 "TypeScript
를 사용하려면 다음과 같이 설정해야합니다"라는 블로그 글만 따라 설정을 하고 나서 제대로 작동한다는 것만 판단을 하고 난 이후에는 별 달리 이 부분을 건드리지 않았다. 지금 프로젝트가 끝나고 정리할 수 있는 시간을 갖는 동안 내가 어떤 설정을 했었는지 알아보기 위해서 이렇게 포스팅을 남겨본다.
[프로젝트에 적용된 설정값 tsconfig.json]
{
"compilerOptions": {
/* Language and Environment */
"target": "es2016",
/* Modules */
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noImplicitReturns": false,
"strictPropertyInitialization": false,
}
}
내가 사용한 설정들은 위와 같다. 적어도 위에서 사용한 설정들의 역할들을 정리해보려고 한다.
어떤 자바스크립트 버젼으로 컴파일할지 정하는 필드다. 타입스크립트 공식 문서에서는 대부분의 웹환경에서 es6
을 지원하고 있기때문에 es6
으로 지정해두는 것을 추천하고 있다. 이외의 버젼으로 컴파일을 하게 된다고 하면, 만들어지는 .js
파일이 구동되는 환경이 해당 버젼의 자바스크립트를 확인할 필요가 있어보인다.
컴파일되는 파일에 적용되는 모듈형식을 지정한다. 타입스크립트 공식 문서에서는 노드 프로젝트에서 타입스크립트를 사용할 때는, "CommonJs"를 설정하는 것을 추천하고 있다. 대소문자는 구별을 하지 않는 것 같다.
헷갈린 점은 이 필드에서 하는 설정이, 컴파일을 하기 전 작성하는 ts 파일에서 사용하는 module 불러오기 방식을 지정하는 줄 알았다. 하지만 컴파일 후 만들어지는 파일이 작동되는 환경에서, 사용 가능한 module을 지정해주는 것이었다.
outDir에 경로를 설정해두면, tsconfig.json이 있는 파일위치로부터 상대주소로, 혹은 파일위치와 상관없는 절대주소로 컴파일된 .js
파일이 생성된다. 이번 같은 경우는 따로 명칭을 지정 안 하니까 npm run dev
로 지정된 app.ts
파일명과 동일한 app.js
파일이 생성되었다.
npm run dev
로 실행시키는 스크립트는 다음과 같다.
[package.json 중]{ ...생략 "dev": "nodemon --watch \"src/**/*.ts\" --exec \"ts-node\" src/app.ts", ...생략 }
이 필드에 지정된 디렉터리 경로에서부터 컴파일을 하게된다.
별다른 문제가 없다면, strict
필드에 설정을 하는 값은 true
를 권장한다. TypeScript
에서 제공하는 주요한 타입 확인 기능을 true로 설정해주기 때문이다. 우선 true로 설정한 이후에 필요하지 않은 타입 확인 기능을 다른 필드에서 안 하게끔 설정해주는 방식을 추천한다.
다음은 strict로 인하여 true로 지정되는 값들이다.
- alwaysStrict
- strictNullChecks ★
- strictFunctionTypes ★
- strictPropertyInitialization
- noImplicitAny
- noImplictThis
- useUnknownInCatchVariables
모듈 해석 방식을 지정해주는 필드다. module
필드에서 CommonJS
를 지정해줬으면 node
로 지정해주는 것도 괜찮을 것 같다.
다음은 moduleResolution 필드에 올 수 있는 값들이다.
classic
node
node16
nodenext
기본값(false)으로 TypeScript
는 CommonJS/AMD/UMD 모듈 형식을 ES6 모듈 형식처럼 다룬다고 한다.
다음은 공식 문서에서 드는 예시다.
import * as moment from "moment"
= const moment = require("moment")
import moment from "moment"
= const moment = require("moment").default
하지만 위에서 든 예시는 다음과 같은 문제를 발생시킨다고 한다.
TypeScript
는 =require("x")
의 형식으로 모듈을 불러오기 때문에 함수를 임포트해와 호출할 수 있게 허용한다. 이는 ES6에서는 허용되지 않기 때문에 컴파일 과정에서 오류를 발생시킨다.TypeScript
의 엄격한 규제를 충족하지 못한다.이를테면
esModuleInterop
를false
를 이용하면 express 모듈을 불러올 때 다음과 같이 작성해야 한다.import * as express from "express";
이는
express
프레임워크에 해당하는 모듈이 반환할 때default
를 지정해서 반환하지 않고 있기 때문이다.
esModuleInterop
를true
로 설정하면 다음과 같이 불러올 수 있다.import express from "express";
TypeScript
코드 작성 중 함수에 리턴값을 지정할 필요가 없다. 타입스크립트 설정으로 strict
가 적용되어 있어도 true
로 지정되지 않아 따로 false
를 지정할 필요가 없었는데 설정을 급하게 따라하다보니 필요없는 설정을 해주었다.
타입스크립트 설정으로 strict
가 적용되어 있으면 true
로 설정되는 컴파일러가 확인하는 항목이다. 클래스 프로퍼티를 선언하면, 생성자 함수에서 해당 프로퍼티를 초기화 시켜줘야만 한다.
typeorm을 이용하여 프로젝트와 MySQL을 연동해줬다. DB 스키마를 생성할 때 클래스를 선언해주는데, 생성자 함수를 통해 설정해준 프로퍼티들을 초기화하지 않으니 문제가 발생했다. 문제를 없에기 위하여
false
로 지정해줬었는데true
로 해도 다음과 같이 각 프로퍼티에!
를 붙여 작성하면 문제가 발생하지 않는다.!
는 해당 프로퍼티에 값이 무조건 할당되어야 한다는 의미다.[User Entity 클래스 선언 코드]
@Entity() export default class User { @PrimaryGeneratedColumn() id!: number @Column({unique:true}) address!: string @Column() name!: string @Column() createdAt!: Date }
위 설정 항목은 TypeScript
에서 데코레이터 문법을 사용할 수 있게 하는 설정인데, 여기에서 설명하고자 하면 글이 길어지기 때문에 다른 포스팅으로 다뤄보도록 하겠다.