...
타입스크립트 컴파일 설정
tsconfig.json은 타입스크립트를 자바스크립트로 변환 시키는 컴파일 설정을 한꺼번에 정의 해놓는 파일이라고 보면 된다. 프로젝트를 컴파일 하는데 필요한 루트 파일, 컴파일러 옵션 등을 상세히 설정할 수 있다.
보통 tsconfig.json 파일은 TypeScript 프로젝트의 루트 디렉토리(Root Directory)에 위치된다. 그래서 tsconfig.json 파일이 프로젝트에 있다면 vscode는 우리가 타입스크립트로 개발한다는 것을 인식하게 되는 것이다.
tsconfig에서 옵션들을 미리 정의해 놓으면, 더이상 컴파일 할때 명령어에 일일히 대상 파일이나 옵션을 지정하지 않아도 된다. 그래서 tsc 나 ts-node 명령어를 그냥 실행하게 되면, 현재 폴더에 있는 tsconfig 설정 내용을 기준으로 프로젝트에서 소스들을 변환 작업(컴파일)을 진행하게 된다. 만약 현재 폴더에 tsconfig 설정 파일이 없다면 프로젝트 폴더 내에서 상위 폴더의 경로를 검색해 나간다.
tsconfig 생성
다음 명령어를 실행하면 미리 작성된 tsconfig.json 파일을 자동으로 만들어준다. 파일을 열어보면 사진에서 보다 시피 무수히 많은 옵션들이 있는걸 볼 수 있다.
> tsc --init
tsconfig 전역 속성
tsconfig 전역 속성이란, 파일의 최상위에 위치하고 있는 속성들을 일컫는다.
{
// TypeScript 컴파일러의 옵션들을 지정하는 속성
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"strict": true,
"sourceMap": true
// ... 무수히 많은 속성들
},
// 컴파일할 파일들의 개별 목록을 지정하는 속성
"files": ["src/main.ts", "src/utils.ts"],
// 컴파일할 파일들을 지정하는 속성 (와일드 카드 패턴으로 묶어 표현)
"include": [ "src/**/*.ts" ],
// 컴파일 대상에서 제외할 파일들을 지정하는 속성
"exclude": [ "node_modules", "**/*.test.ts" ],
// 다른 tsconfig.json 파일을 상속받아서 설정을 재사용할 수 있게 해주는 속성
"extends": "./configs/base.json",
// 여러 개의 하위 프로젝트로 구성된 프로젝트의 의존 관계를 지정하는 속성
"references": [
{ "path": "./subproject1" },
{ "path": "./subproject2" }
],
// 타입 습득(type acquisition)과 관련된 옵션들을 지정하는 속성
"typeAcquisition": {
"enable": true,
"include": ["jquery"],
"exclude": ["react"]
},
// watch 모드와 관련된 옵션들을 지정하는 속성
"watchOptions": {
"watchFile": "useFsEvents",
"watchDirectory": "useFsEvents",
"fallbackPolling": "dynamicPriority"
}
}
정말 많은 전역 속성들이 있지만, 이중에서 주로 쓰이는 다섯가시 속성으로는 compilerOptions, files, include, exclude, extends 정도가 있다.
files
프로젝트에서 컴파일할 파일들의 목록을 명시적으로 지정하는 속성이다.
files 속성은 밑에서 배울 exclude보다 우선순위가 높다. 만일 이 속성이 생략되면 include와 exclude 속성으로 컴파일 대상을 결정한다.
{
"files": [ // 파일 확장자까지 정확히 작성해줘야 한다
"src/main.ts",
"src/utils.ts",
"src/types.d.ts"
]
}
extends
extends는 다른 tsconfig.json 파일의 설정들을 가져와 재사용할 수 있게 해주는 옵션이다. 보통 extends 속성은 tsconfig.json 파일의 최상위에 위치한다.
예를들어 config/base.json 파일의 속성 설정을 현 tsconfig.json 파일에 포맷이 맞으면 base파일의 설정을 상속 받게 된다.
// config/base.json
{
"compilerOptions": {
"noImplicitAny": true,
"strictNullChecks": true
}
}
{
"extends": "./configs/base",
"compilerOptions": {
"strictNullChecks": false
},
"files": [
"src/main.ts",
"src/utils.ts",
"src/types.d.ts"
]
}
include
include 속성은 files 속성과 같이 프로젝트에서 컴파일할 파일들을 지정하는 속성이지만, 와일드 카드 패턴으로 지정한다는 점에서 차이가 있다. 또한 include는 files 속성과는 달리 exclude보다 약해 include에 명시되어 있어도 exclude에도 명시되어 있으면 제외 되게 된다.
{
"compilerOptions": {
...
},
"include": [
"src/*.ts", // src 디렉토리에 있는 모든 .ts 파일
"dist/test?.ts" // dist 디렉토리에 있는 test1.ts, test2.ts , test3.ts ..등에 일치
"test/**/*.spec.ts" // test 디렉토리와 그 하위 디렉토리에 있는 모든 .spec.ts 파일
]
}
와일드 카드 패턴이란 tsconfig.json 파일에서 include나 exclude 속성에 사용할 수 있는 파일이나 디렉토리를 그룹화하여 일치시키는 기호라고 보면 된다.
- * : 해당 디렉토리에 있는 모든 파일
- ? : 해당 디렉토리에 있는 파일들의 이름 중 한 글자라도 포함하면 해당
- ** : 해당 디렉토리의 하위 디렉토리의 모든 파일을 포함
exclude
exclude 속성은 프로젝트에서 컴파일 대상에서 제외할 파일들을 와일드카드 패턴으로 지정하는 속성이다. 즉, include의 반대 버전이라 보면 된다.
{
"compilerOptions": {
...
},
"exclude": [
"node_modules", // node_modules 디렉토리를 제외
"**/*.test.ts" // 모든 .test.ts 파일을 제외
]
}
compilerOptions
컴파일 대상 파일들을 어떻게 변환할지 세세히 정하는 옵션이다. 정말 많은 옵션들이 있고, 이들중 애용되는 옵션들은 바로 다음 섹션에서 자세히 다룬다.
{
"compilerOptions": {
/* 기본 옵션
* ------------------------------------------------------------------------------------------------------------------------------------------------ */
"incremental": true, /* 증분 컴파일 활성화 */
"target": "es5", /* ECMAScript 목표 버전 설정: 'ES3'(기본), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "esnext", /* 생성될 모듈 코드 설정: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
"lib": ["dom", "dom.iterable", "esnext"], /* 컴파일 과정에 사용될 라이브러리 파일 설정 */
"allowJs": true, /* JavaScript 파일 컴파일 허용 */
"checkJs": true, /* .js 파일 오류 리포트 설정 */
"jsx": "react", /* 생성될 JSX 코드 설정: 'preserve', 'react-native', or 'react'. */
"declaration": true, /* '.d.ts' 파일 생성 설정 */
"declarationMap": true, /* 해당하는 각 '.d.ts'파일에 대한 소스 맵 생성 */
"sourceMap": true, /* 소스맵 '.map' 파일 생성 설정 */
"outFile": "./", /* 복수 파일을 묶어 하나의 파일로 출력 설정 */
"outDir": "./dist", /* 출력될 디렉토리 설정 */
"rootDir": "./", /* 입력 파일들의 루트 디렉토리 설정. --outDir 옵션을 사용해 출력 디렉토리 설정이 가능 */
"composite": true, /* 프로젝트 컴파일 활성화 */
"tsBuildInfoFile": "./", /* 증분 컴파일 정보를 저장할 파일 지정 */
"removeComments": true, /* 출력 시, 주석 제거 설정 */
"noEmit": true, /* 출력 방출(emit) 유무 설정 */
"importHelpers": true, /* 'tslib'로부터 헬퍼를 호출할 지 설정 */
"downlevelIteration": true, /* 'ES5' 혹은 'ES3' 타겟 설정 시 Iterables 'for-of', 'spread', 'destructuring' 완벽 지원 설정 */
"isolatedModules": true, /* 각 파일을 별도 모듈로 변환 ('ts.transpileModule'과 유사) */
/* 엄격한 유형 검사 옵션
* ------------------------------------------------------------------------------------------------------------------------------------------------ */
"strict": true, /* 모든 엄격한 유형 검사 옵션 활성화 */
"noImplicitAny": true, /* 명시적이지 않은 'any' 유형으로 표현식 및 선언 사용 시 오류 발생 */
"strictNullChecks": true, /* 엄격한 null 검사 사용 */
"strictFunctionTypes": true, /* 엄격한 함수 유형 검사 사용 */
"strictBindCallApply": true, /* 엄격한 'bind', 'call', 'apply' 함수 메서드 사용 */
"strictPropertyInitialization": true, /* 클래스에서 속성 초기화 엄격 검사 사용 */
"noImplicitThis": true, /* 명시적이지 않은 'any'유형으로 'this' 표현식 사용 시 오류 발생 */
"alwaysStrict": true, /* 엄격모드에서 구문 분석 후, 각 소스 파일에 "use strict" 코드를 출력 */
/* 추가 검사 옵션
* ------------------------------------------------------------------------------------------------------------------------------------------------ */
"noUnusedLocals": true, /* 사용되지 않은 로컬이 있을 경우, 오류로 보고 */
"noUnusedParameters": true, /* 사용되지 않은 매개변수가 있을 경우, 오류로 보고 */
"noImplicitReturns": true, /* 함수가 값을 반환하지 않을 경우, 오류로 보고 */
"noFallthroughCasesInSwitch": true, /* switch 문 오류 유형에 대한 오류 보고 */
"noUncheckedIndexedAccess": true, /* 인덱스 시그니처 결과에 'undefined' 포함 */
/* 모듈 분석 옵션
* ------------------------------------------------------------------------------------------------------------------------------------------------ */
"moduleResolution": "node", /* 모듈 분석 방법 설정: 'node' (Node.js) 또는 'classic' (TypeScript pre-1.6). */
"baseUrl": "./", /* 절대 경로 모듈이 아닌, 모듈이 기본적으로 위치한 디렉토리 설정 (예: './modules-name') */
"paths": {}, /* 'baseUrl'을 기준으로 상대 위치로 가져오기를 다시 매핑하는 항목 설정 */
"rootDirs": [], /* 런타임 시 프로젝트 구조를 나타내는 로트 디렉토리 목록 */
"typeRoots": [], /* 유형 정의를 포함할 디렉토리 목록 */
"types": [], /* 컴파일 시 포함될 유형 선언 파일 입력 */
"allowSyntheticDefaultImports": true, /* 기본 출력(default export)이 없는 모듈로부터 기본 호출을 허용 (이 코드는 단지 유형 검사만 수행) */
"esModuleInterop": true, /* 모든 가져오기에 대한 네임스페이스 객체 생성을 통해 CommonJS와 ES 모듈 간의 상호 운용성을 제공. 'allowSyntheticDefaultImports' 암시 */
"preserveSymlinks": true, /* symlinks 실제 경로로 결정하지 않음 */
"allowUmdGlobalAccess": true, /* 모듈에서 UMD 글로벌에 접근 허용 */
/* 소스맵 옵션
* ------------------------------------------------------------------------------------------------------------------------------------------------ */
"sourceRoot": "./", /* 디버거(debugger)가 소스 위치 대신 TypeScript 파일을 찾을 위치 설정 */
"mapRoot": "./", /* 디버거가 생성된 위치 대신 맵 파일을 찾을 위치 설정 */
"inlineSourceMap": true, /* 하나의 인라인 소스맵을 내보내도록 설정 */
"inlineSources": true, /* 하나의 파일 안에 소스와 소스 코드를 함께 내보내도록 설정. '--inlineSourceMap' 또는 '--sourceMap' 설정이 필요 */
/* 실험적인 기능 옵션
* ------------------------------------------------------------------------------------------------------------------------------------------------ */
"experimentalDecorators": true, /* ES7 데코레이터(decorators) 실험 기능 지원 설정 */
"emitDecoratorMetadata": true, /* 데코레이터를 위한 유형 메타데이터 방출 실험 기능 지원 설정 */
/* 고급 옵션
* ------------------------------------------------------------------------------------------------------------------------------------------------ */
"skipLibCheck": true, /* 선언 파일 유형 검사 스킵 */
"forceConsistentCasingInFileNames": true /* 동일한 파일에 대한 일관되지 않은 케이스 참조를 허용하지 않음 */
}
}
compilerOptions 옵션 설명
위에서 봤듯이 옵션 종류가 굉장히 많다. 이들을 하나하나 모두 익힐 필요는 없고, 이중에서 유용한 옵션을 위주로 모아 정리해 보았다.
Language and Environment 옵션
target
어떠한 버전의 JavaScript 코드로 컴파일 할지 지정한다. 만약 코드가 구식의 환경에서 배포된다면 더 낮은 버전을 지정해야 하고, 신식의 환경에서만 배포된다는 보장이 있다면 더 높은 타겟으로 지정해도 된다. (자바스크립트 버전 지정 값을 넣지 않으면 default로 es5로 컴파일 된다)
다만 타입스크립트 소스 코드에 Promise 코드가 있을 경우, 이는 ES5에서 지원해주지 않기 때문에 Typescript를 컴파일 하면 오류가 발생하니 이부분은 유의해야 한다.
대부분의 브라우저는 모든 ES6를 지원하기 때문에, 보통 ES6로 놓고 사용되는 편이다.
target 프로퍼티는 lib 프로퍼티의 기본값도 자동으로 결정 시킨다. 따라서 target 프로퍼티와 lib 프로퍼티를 권장되는 방식대로 직접 맞출 수도 있지만, 편의를 위해 그냥 target 프로퍼티만 지정할 수도 있다.
target 프로퍼티 값중에 ESNext 옵션값이 있는데, 가장 최신 기능의 자바스크립트 버전을 가리키는 값이다. 이 설정은 주의 깊게 사용되어야 하는데, 왜냐하면 현재 TypeScript의 버전에 따라 ESNext가 가리키는 버전이 달라질 수 있기 때문이다.
"compilerOptions": {
"target": "ES6" // 어떤 버전의 자바스크립트로 컴파일 될 것인지 설정
// 'es3', 'es5', 'es2015', 'es2016', 'es2017','es2018', 'esnext' 가능
}
lib
lib 옵션은 컴파일에 필요한 JavaScript 내장 라이브러리를 지정할 수 있다. Math API, document API 등이 그 예시이다.
이 프로퍼티가 지정되어 있지 않다면 target 프로퍼티에 지정된 버전에 따라 필요한 타입 정의들에 대한 정보가 자동으로 지정된다. 예를 들어, target 프로퍼티가 ES6 혹은 그 이상의 버전으로 지정되었는데, lib 프로퍼티가 지정되지 않다면 자동으로 lib 프로퍼티에는 ES2015(lib.es2015.d.ts 파일) 등의 라이브러리들이 지정되기 때문에 기본적으로 타입 정보를 전역으로 참조할 수 있게 되는 것이다.
lib 프로퍼티를 지정하지 않을 때 자동으로 설정되는 값은 다음과 같다.
- target이 es3이면 디폴트로 lib.d.ts를 사용
- target이 es5이면, 디폴트로 dom, es5, scripthost를 사용
- target이 es6이면, 디폴트로 dom, es6, dom.iterable, scripthost를 사용
"compilerOptions": {
"lib": ["es5", "es2015.promise", "dom"], // 컴파일 과정에 사용될 라이브러리 파일 설정
/*
es5: global type을 사용하기 위함 (Array, Boolean, Function 등..)
es2015.promise: Promise를 사용하기 위함
dom: setTimeout, console.log 등 dom에서 지원해주는 기능들을 사용하기 위함
*/
}
experimentalDecorators / emitDecoratorMetadata
타입스크립트의 @Decorator를 사용하기 위해서는 true로 둬야 작동된다.
"compilerOptions": {
"experimentalDecorators": true /* ES7 데코레이터(decorators) 실험 기능 지원 설정 */
"emitDecoratorMetadata": true /* 데코레이터를 위한 유형 메타데이터 방출 실험 기능 지원 설정 */
}
function methodDecorator() {
console.log('method');
return function (target: any, property: any, descriptor: any) {};
}
function propertyDecorator(writable: boolean = true) {
console.log('property');
return function (target: any, decoratedPropertyName: any): any {};
}
class Test {
@propertyDecorator()
property = 'property';
@methodDecorator()
test(param1: string) {
console.log('test1');
}
}
jsx
.tsx 확장자의 컴파일 결과 JSX 코드를 어떻게 컴파일할지 결정한다.
- react : .js 파일로 컴파일 된다. (JSX 코드는 React.createElement() 함수의 호출로 변환됨)
- react-jsx : .js 파일로 컴파일 된다. (JSX 코드는 _jsx() 함수의 호출로 변환됨)
- react-jsxdev : .js 파일로 컴파일 된다. (JSX 코드는 _jsx() 함수의 호출로 변환됨)
- preserve : .jsx 파일로 컴파일 된다. (JSX 코드가 그대로 유지됨)
- react-native : .js 파일로 컴파일 된다. (JSX 코드가 그대로 유지됨)
"compilerOptions": {
"jsx": "preserve" // tsx 파일을 jsx로 어떻게 컴파일할 것인지 'preserve', 'react-native', 'react'
}
Modules 옵션
rootDir
루트 디렉토리 기준을 변경한다. js 아웃풋 경로에 영향을 줄 수 있다.
module / moduleResolution
프로그램에서 사용할 모듈 시스템을 결정한다.
만일 import 구문을 es6로 컴파일 했을때, 동일하게 import로 컴파일되어 commonJS환경의 node로 실행시 오류가 발생 할 수도 있다.
따라서 import 구문을 require 구문으로 컴파일을 해줘야할때 module의 속성값을 commonJS로 지정하면 된다.
- CommonJS (target 프로퍼티가 ES3 혹은 ES5로 지정되었을 때의 기본값)
- ES6/ES2015 (target 프로퍼티가 ES6 혹은 그 이상의 버전으로 지정되었을 때의 기본값)
- 나머지 (ES2020, ESNext, AMD, UMD, System, None)
참고로 module 프로퍼티는 moduleResolution 프로퍼티의 기본값도 결정한다.
module이 commonjs면 노드에서 작동하는 것을 의미하므로, moduleResoultion 키 값은 node이며, 만일 module이 amd(웹)면 classic으로 설정된다.
"compilerOptions": {
"module": "commonjs", /* 생성될 모듈 코드 설정: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
"moduleResolution": "node", /* 모듈 분석 방법 설정: 'node' (Node.js) 또는 'classic' (TypeScript pre-1.6). */
}
baseURL / paths
import 구문의 모듈 해석 시에 기준이 되는 경로를 지정한다.
개발을 하다 보면, 노드 패키지 이외에도, 직접 만든 소스 파일을 import 시켜야 하는 때가 발생한다. 그래서 파일의 상단에는 다음과 같이 전역경로 와 상대경로 기준으로 각각 import 하게 된다.
import styled from 'styled-components'; // 노드 패키지일 경우 최상단 경로에 있는 node_modules 폴더를 자동 인식
import { TextField } from '../../../../components/textfield'; // 직접 만든 사용사 소스 파일이 있을 경우 상대경로로 가져와야 한다.
...
‘../../../../index.ts’같이 import 하는 이런 방식이 좀 예쁘진 않아도 일단 작동하는데는 문제가 없지만, 추후 계속 프로젝트를 작성하거나 리팩토링 할 때 문제가 발생할 수 있다.
예를들어 상대 경로란 현재 위치하고 있는 파일 경로에 따라 얼마든지 달라질수가 있기 때문에, 만일 다른 경로에 파일을 만들어서 동일한 모듈을 import 하려고 하면, 위치 기준점이 달라지기 때문에 다르게 상대경로를 찾아 들어가야 되서 굉장히 번거로워 진다.
바로 이때 baseUrl 속성 과 paths 속성을 설정하면 절대경로로 import 할수 있게 된다. 그럼 아래와 같이 절대경로로 깔끔하게 작성할 수 있다.
import styled from 'styled-components';
import { TextField } from '@components/textfield';
...
첫 번째로 baseUrl 속성에 기본 경로를 설정해 주고 그 바로 아래에 paths 속성에 절대 경로를 지정하고 싶은 경로들을 지정해 주면 된다. 추가적으로 outDir 도 설정해준다.
{
"compilerOptions": {
"baseUrl": "./", // 절대 경로 모듈이 아닌, 모듈이 기본적으로 위치한 디렉토리 설정
"paths": { // 'baseUrl'을 기준으로 상대 위치로 가져오기를 다시 매핑하는 항목 설정
"@components/*": [
"src/components/*" // import {} from '@components/파일' 할때 어느 경로로 찾아들어갈지 paths 설정
],
"@utils/*": [
"src/utils/*"
],
},
"outDir": "./dist", // 컴파일할때 js 파일 위치 경로 지정
},
}
그러나 실제 ts-node를 이용해 소스 파일을 실행해보면 오류가 난다. 왜냐하면 tsconfig.json 설정은 경로 alias만 준것이지 실제 경로를 바꾼게 아니기 때문이다.
따라서 별도로 tsconfig-paths 와 tsc-alias 라는 모듈이 설치해주어야 한다.
[ tsconfig-paths ]
tsconfig.json 내에 baseurl 이나 paths필드에 명시된 모듈을 실제로 호출하게 도와주는 라이브러리
[ tsc-alias ]
js 파일로 컴파일되면 baseurl 이나 paths 필드로 명시된 경로가 그대로 트랜스파일링 되서 js 모듈을 인식할수 없는 현상이 일어나게 되는데, 이 패키지를 이용하면 컴파일된 경로를 상대경로로 바꿔서 해결이 가능하다.
> npm i -D tsconfig-paths tsc-alias
그리고 tsconfig.json 파일에서 전역 속성으로 다음과 같이 추가 설정을 해준다.
{
"compilerOptions": {
"baseUrl": "./"
"path": ...
},
// 전역 속성으로 추가해준다.
"ts-node": {
"require": ["tsconfig-paths/register"]
}
}
조심해야 할점은, @로 시작하는 라이브러리를 npm을 통해 받아서 사용할때 alias 명칭과 중복되지 않게 등록해야 한다.
그리고 ts-node index.ts 명령어를 실행해보면, @경로를 잘 찾아들어가는 걸 확인 할 수 있다. 배포환경의 빌드 같은 경우, 컴파일 명령어를 다음과 같이 하면 된다.
> tsc && tsc-alias
package.json의 script도 설정해주면 좋자.
"scripts": {
"build": "tsc --project tsconfig.json && npx tsc-alias -p tsconfig.json",
}
types / typeRoots
tsconfig는 기본적으로 node_modules 폴더를 제외하지만, 라이브러리의 타입을 정의해놓는 @types 폴더는 컴파일에 자동으로 경로에 포함된다. 그런데 만약 이 @types의 기본 경로를 변경하고 싶다면 아래와 같이 지정할 수 있다.
"compilerOptions": {
"typeRoots": ["./my-tslib"], // 컴파일 목록에 자동으로 포함시킬 패키지들의 기준 디렉토리
// .d.ts 파일을 읽을 폴더를 node_modules/@types에서 node_modules/my-tslib로 변경
"types": ["node", "jest", "express"], // typeRoots 디렉토리 내에 존재하는 패키지들 중 어떤 패키지들을 컴파일 목록에 포함시킬지
// 만약 types가 지정되어 있지 않다면 typeRoots에 지정된 경로의 패키지들은 전부 컴파일 목록에 자동으로 포함
}
resolveJsonModule
확장자가 .json인 모듈의 import를 허용하는 설정이다. 생각해 보면 Node.js 자바스크립트 프로젝트에서 json 설정 파일을 import해서 자주 사용해온걸 떠올릴 것이다. 타입스크립트도 가능할 것이라 생각하지만, json의 프로퍼티들을 싹다 타입을 지정해야 사용이 가능하다.
이 옵션은 json의 타입을 자동으로 설정해줘서 따로 변환 작업없이 타입스크립트에서 json 파일 데이터들을 곧바로 사용할 수 있도록 해준다.
예를 들어 다음과 같은 json 데이터가 있다고 하자.
{
"name":"홍길동",
"age": 54,
"height": 170,
"married": false
}
원래라면 이렇게 ts 파일에서 사용할수 없게 막혀있다.
resolveJsonModule 옵션을 true로 설정해주면, 다음과 같이 자동으로 타입이 매핑되어 사용이 가능해진다.
"compilerOptions": {
"resolveJsonModule": true, // ts 파일에서 json imoprt 허용
}
Interop Constraints 옵션
esModuleInterop
라이브러리 중에서는 amd(웹) 방식을 전제로 구현된 라이브러리가 있는데 commonjs 방식으로 동작하는 TS에서는 혼란을 줄 수 있다. 상호 운용적(interoperable)으로 사용하기 위해서는 가능한 true로 지정해 놓고 타입스크립트 코딩을 하는것을 권한다.
"compilerOptions": {
"esModuleInterop": true, /* 모든 가져오기에 대한 네임스페이스 객체 생성을 통해 CommonJS와 ES 모듈 간의 상호 운용성을 제공 */
}
// esModuleInterop: true일 경우 가능함
import React from "react";
// false인 경우 다음과 같이 import 해야 함
import * from React from "react";
forceConsistentCasingInFileNames
파일의 이름을 대소문자 판별하게 하는 옵션이다.
프로그래밍 세계에선 같은 알파벳이라도 대소문자를 모두 구분하기 때문에 이 옵션은 가능한 true로 해놓고 사용하기를 권장한다.
JavaScript Support 옵션
allowJs
TypeScript 프로젝트에서 JavaScript 파일도 사용할 수 있도록 하는 설정이다. allowJs: true이면 JavaScript 파일들도 타입스크립트 프로젝트에서 import 될 수 있다.
기본적으로 타입스크립트는 .js 확장자를 허용하지 않는다. 그래서 만일 자바스크립트를 타입스크립트로 바꾸는 프로젝트가 진행중이라면 곤란함을 겪게 된다. 따라서 이 속성은 JavaScript 프로젝트를 TypeScript 프로젝트로 바꾸려 할 때 점진적으로 변환하기 위한 용도로 사용된다.
"compilerOptions": {
"allowJs": true,
}
checkJs
ts 파일 뿐만 아니라, js 파일에 있는 에러도 보고하라는 옵션이다. 보통 allowJS 속성과 함께 사용된다.
"compilerOptions": {
"allowJs": true, // js 파일들 ts에서 import해서 쓸 수 있는지
"checkJs": true, // 일반 js 파일에서도 에러체크 여부
}
Emit 옵션
outFile
일반적인 형태로는 하나의 파일로 만들수 없지만, 번들러 형태로 지원하여 하나로 만든다.
단, 모듈이 시스템 혹은 amd와 같은 형태로 지원되어야 파일을 하나로 만들수 있어서, 차라리 따로 웹팩을 사용하지 이 기능을 이용하지는 않아 중요도가 낮은 옵션이다.
outDir
기본적으로 컴파일을 진행하면 .ts와 같은 경로에 .js 결과물을 생성하는데, outDir 옵션으로 경로를 수정하여 컴파일된 js 파일들을 담을 폴더를 지정해줄 수 있다.
"compilerOptions": {
"outDir": "./dist"
}
noEmit
타입스크립트를 컴파일하면, JavaScript 변환 파일을 만들어 내지 않도록 하는 설정이다.
이는 곧 타입스크립트를 에디터 통합 기능을 제공하기 위한 도구 혹은 소스 코드 타입 체커로만 사용하게 되는 꼴이 된다.
만일 Babel이나 swc와 같은 또 다른 도구가 변환하는 작업을 대신 담당하는 경우 사용되는 옵션이라고 이해하면 된다.
"compilerOptions": {
"noEmit": true,
}
sourceMap
컴파일된 파일 디렉터리에 .js.map 파일이 만들어진다.
이 소스맵 파일은 변환된 js코드가 ts의 어디에 해당하는 지를 알려준다. 디버깅 작업에 매우 유용하다.
"compilerOptions": {
"sourceMap": true, /* 소스맵 '.map' 파일 생성 설정 */
}
실제로 타입스크립트 프로젝트를 배포하고, 브라우저에서 개발자모드를 이용해 source 탭에 보면, 브라우저는 js만 인식하지만 매핑 파일에 의해 ts 파일을 인식하는걸 볼 수 있다.
이렇게 직접 타입스크립트 파일에 잘못된 부분이 있으면 직접 디버깅 할 수 있다.
downlevelIteration
타입스크립트에서 제너레이터 function* {}, yeild... 를 사용하기 위한 옵션
코드를 이전 버전의 js로 컴파일하고 for loop로 작업하면 컴파일이 제대로 작동하지 않을 수 있어, 이 속성을 설정을 해놓으면 정확도가 올라가지만 js코드량이 늘어나기 때문에, 의도한대로 loop가 작동하지 않을 때만 사용하길 권한다.
"compilerOptions": {
"downlevelIteration": true, //* 'ES5' 혹은 'ES3' 타겟 설정 시 Iterables 'for-of', 'spread', 'destructuring' 완벽 지원 설정 */
}
removeComments
컴파일 시 타입스크립트 소스의 주석을 모두 제거하는 것을 설정한다.
"compilerOptions": {
removeComments": true, // true면 컴파일된 js에 기존의 주석을 모두 제거
}
noEmitOnError
원래는 타입스크립트에 구문 에러가 발생하더라도, 컴파일하면 js파일을 생성하는데, 위 설정을 true로 설정하면 에러가 발생한 ts파일은 컴파일을 막는다.
"compilerOptions": {
noEmitOnError": true, // 컴파일 에러가 있으면 js 컴파일 하지 않음
}
declaration
이 옵션을 true로 하면 TS파일을 JS로 컴파일하는 과정에서 JS파일과 함께 d.ts 파일이 생성되게 한다.
객체랑 함수를 쓰다보면 타입을 커스텀하는 경우가 온다. 이때 타입들을 ts파일에 넣어도 되지만 용도가 다르기때문에 분리하는 것이 좋다. 그럴때 d.ts파일을 만들어 따로 타입만을 관리하는데 이럴때 사용되는 옵션이다.
"compilerOptions": {
"declaration": true, //컴파일시 .d.ts 파일도 자동으로 함께생성 (현재쓰는 모든 타입이 정의된 파일)
}
Type Checking 옵션
strict
타입스크립트의 각종 타입 체킹 동작을 전부 활성화한다.
사실상 이 옵션을 쓰지않는것은 곧 타입스크립트를 쓰지 않는 다는 것과 같다. 따라서 기본으로 활성화 되어 있다.
"compilerOptions": {
"strict": true /* 모든 엄격한 유형 검사 옵션 활성화 */
}
이 프로퍼티를 true로 지정하면 strict mode family 프로퍼티들을 전부 true로 지정하는 것과 동일하다.
만일 사소한 부분에도 너무 지나치게 빨간줄을 긋는게 불편하다면, 선택적으로 몇 개의 strict mode family 프로퍼티를 false로 지정하는 식으로 설정하면 된다.
[strict mode family 프로퍼티들]
- alwaysStrict 프로퍼티
- strictNullChecks 프로퍼티
- strictBindCallApply 프로퍼티
- strictFunctionTypes 프로퍼티
- strictPropertyInitialization 프로퍼티
- noImplicitAny 프로퍼티
- noImplicitThis 프로퍼티
noImplicitAny
명시적이지 않은 any 타입이 지정될 경우 표현식과 선언에 사용하면 에러 발생 시킨다.
예를들어 타입스크립트가 추론을 실패해서 any로 지정되면 빨간줄이 뜨게 되는데, 이때 직접 any라고 지정해야 빨간줄이 사라진다.
위의 strict 옵션을 true로 하면 noImplicitAny 옵션도 자동으로 true가 되서 나타나는 현상인데, 이때 이 옵션을 false로 지정하면 아래와 같이 any 타입을 명시적으로 지정 안해도 오류가 사라지게 된다.
"compilerOptions": {
"strict": true,
"noImplicitAny": false /* 명시적이지 않은 'any' 유형으로 표현식 및 선언 사용 시 오류 발생 */
}
function methodDecorator() {
console.log('method');
return function (target, property, descriptor) {}; // noImplicitAny: false로 하면, 명시적 any를 안써도 에러가 안난다.
}
suppressImplicitAnyIndexErrors
nolmplicitAny를 사용할 때 인덱스 객체에 인덱스 시그니처가 없는 경우 오류가 발생하는 것을 예외 처리 해준다.
예를들어 suppressImplicitAnyindexErrors옵션을 true로 설정해주면, person 객체에 age 라는 프로퍼티가 없어도 person['age'] 를 에러를 내주지 않는다.
"compilerOptions": {
"strict": true,
"suppressImplicitAnyIndexErrors": true,
}
const person = {
name: '홍길동',
};
console.log(person['age']); // suppressImplicitAnyIndexErrors: true로 하면 그냥 undefined를 출력한다
noImplicitThis
암시적 any 유형이 있는 this 표현식에서 오류를 발생시킨다.
본래라면 명시적 this를 통해 오류를 해결하지만, this에 any가 오는걸 허용한다면 이 옵션을 false로 지정해주어 빨간줄을 지울 수 있다.
"compilerOptions": {
"strict": true,
"noImplicitThis": false, /* 명시적이지 않은 'any'유형으로 'this' 표현식 사용 시 오류 발생 */
}
class Rectangle {
width: number;
height: number;
constructor(width: number, height: number) {
this.width = width;
this.height = height;
}
getAreaFunction() {
return function () {
return this.width * this.height; // 원래는 명시적 this를 써야하지만, "noImplicitThis": false 하면 안써줘도 된다.
};
}
}
strictNullChecks
null및 undefined 값에 대한 유형을 조정하는 옵션이다.
strickNullChecks를 적용하면, 모든 타입은 null, undefined값을 가질 수 없고 가지려면 union type으로 직접 명시해야 한다.
단, 기본적으로 any에 null, undefined할당 가능하며 void에는 undefined 할당 가능하다.
함수를 선언할 때부터 매개변수와 리턴 값에 정확한 타입을 지정할 수 있는 효과가 있다.
만일 strickNullChecks를 적용하지 않을 경우 모든 타입은 null, undefined값을 할당 가능해진다.
"compilerOptions": {
"strict": true,
"strictNullChecks": false, /* 엄격한 null 검사 사용 */
}
이 옵션은 왠만하면 활성화 해주는게 좋은데, 다음과 같이 미리 에러를 잡아주기 때문이다.
strictFunctionTypes
타입스크립트는 기본적으로 공변적(covariant)인 규칙을 따르지만, 함수의 매개변수 만이 이변량(bivariant)의 구조를 가진다. 따라서 매개변수 타입이 달라도 막 대입할수 있는 현상이 일어나게 되는데, 이를 반공변적(contravariant)으로 설정해주어 이변성의 오류를 해결한다. 하지만 자바스크립트에선 서로의 콜백을 함수에 인자로 전달하는 일이 빈번하기 때문에 오히려 이런 옵션이 활성화 되있는게 거슬릴수 있는데, 이 옵션을 false로 하면 반공병성을 끌수 있다.
"compilerOptions": {
"strict": true,
"strictFunctionTypes": false, /* 엄격한 함수 유형 검사 사용 */
}
function fn(x: string) {
console.log('Hello, ' + x.toLowerCase());
}
type StringOrNumberFunc = (ns: string | number) => void;
// Unsafe assignment
let func: StringOrNumberFunc = fn; // 대입이 가능해진다.
func(10); // Unsafe call - will crash
strictPropertyInitialization
정의되지 않은 클래스의 속성이 생성자에서 초기화되었는지 확인한다.
예를 들어 UserAccount 클래스의 constructor에서는 name 프로퍼티만 초기화해주고 email 프로퍼티는 선언만 하였는데, 이때 너무 강하게 타입 체킹 하는 느낌이 든다면, 이 옵션을 false로 줘서 빨간줄을 해결할 수 있다.
"compilerOptions": {
"strict": true,
"strictPropertyInitialization": false, /* 클래스에서 속성 초기화 엄격 검사 사용 */
}
class UserAccount {
name: string;
accountType = 'user';
address: string | undefined;
email: string; // strictPropertyInitialization: false로 하면 빨간줄이 사라진다.
constructor(name: string) {
this.name = name;
}
}
tsconfig를 수정하는게 마음에 안들면, non-null 단언 연산자를 이용해도 해결 할수 있다.
email!: string; // 어디선가 할당될 것이므로 에러를 무시하라는 의미
strictBindCallApply
function의 내장 함수인 bind, call, apply를 사용할 때 더욱 엄격하게 검사하는 옵션이다.
"compilerOptions": {
"strict": true,
"strictBindCallApply": false, /* 엄격한 'bind', 'call', 'apply' 함수 메서드 사용 */
}
function fn(x: string) {
return parseInt(x);
}
const n1 = fn.call(undefined, '10');
const n2 = fn.call(undefined, false); // strictBindCallApply: false 로 하면 아무거나 넣을 수 있다.
alwaysStrict
컴파일된 자바스크립트 파일에 "use strict" 모드를 사용하도록 명시한다. strict 옵션이 활성화 되어있을경우 기본적으로 이 옵션도 활성화 되며, 만일 이 옵션을 false로 지정하면 컴파일된 자바스크립트 파일에선 strict mode를 쓰지 않게 된다.
"compilerOptions": {
"strict": true,
"alwaysStrict": false, /* 엄격모드에서 구문 분석 후, 각 소스 파일에 "use strict" 코드를 출력 */
}
이 밑은 strict 속성에 국한되지 않은 독립적인 추가 검사 옵션들이다.
noUnusedLocals
쓰지않는 지역변수 있으면 에러내기
noUnusedParameters
쓰지않는 파라미터 있으면 에러내기
noImplicitReturns
함수에서 return 빼먹으면 에러내기
noFallthroughCasesInSwitch
switch문 이상하면 에러내기. 예를들어 switch 문에서 비어 있지 않은 Case라면 반드시 break 문이나 return 문으로 해당 Case를 종료시키도록 에러를 내준다. 이를 통해 의도치 않은 Fallthrough Case에 의한 버그를 예방할 수 있다.
Completeness 옵션
skipLibCheck
타입 체킹을 스킵하도록 하는 설정이다. 타입스크립트에 타입 체킹을 안하면 무슨 의미가 있겠냐 싶지만, 만일 프로젝트의 규모가 크면 라이브러리의 선언 파일들이 매우 방대할 텐데, 그것들을 매번 다시 체크하는 것은 상당한 시간이 소모가 된다. 그래서 이 옵션을 true로 지정하여 선언 파일들의 타입 체크를 생략하도록 하여 컴파일 시간을 줄여주도록 하기 위한 속성이다.
"compilerOptions": {
"skipLibCheck": true, /* 선언 파일 유형 검사 스킵 */
}
# 참고자료
https://it-eldorado.tistory.com/128
https://typescript-kr.github.io/pages/tsconfig.json.html
https://codingapple.com/unit/typescript-tsconfig-json/
https://velog.io/@milkcoke/Typescript-.d.ts-%EC%A0%95%EC%9D%98%ED%95%98%EA%B8%B0
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.