tsc --init
으로 tsconfig.json을 먼저 생성한다.
tsconfig.json의 컴파일 옵션이 무엇이 있으며
프론트엔드와 백엔드에 어떻게 설정해야하는지 정리했다.
백엔드에 타입스크립트를 적용하는 방법은 프론트엔드의 적용방법이나 순서가 많이 다르다.
프론트엔드가 비교적 적용이 쉬우니 프론트엔드에서 먼저 설정을 해보고 백엔드로 넘어가는 것이 좋을 것 같다.
많이 쓰이는 컴파일 옵션이 무엇이 있는 지 한번 훑어보자.
{
"compilerOptions": {
/* https://aka.ms/tsconfig.json 를 방문하면 해당 파일에 대한 더 많은 정보를 얻을 수 있습니다. */
// 옵션은 아래와 같은 형식으로 구성되어 있습니다.
// "모듈 키": 모듈 값 /* 설명: 사용가능 옵션 (설명이 "~ 여부"인 경우 'true', 'false') */
/* 기본 옵션 */
// "incremental": true, /* 증분 컴파일 설정 여부 */
"target": "es5", /* 사용할 특정 ECMAScript 버전 설정: 'ES3' (기본), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 혹은 'ESNEXT'. */
"module": "commonjs", /* 모듈을 위한 코드 생성 설정: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
// "lib": [], /* 컴파일에 포함될 라이브러리 파일 목록 */
// "allowJs": true, /* 자바스크립트 파일 컴파일 허용 여부 */
// "checkJs": true, /* .js 파일의 오류 검사 여부 */
// "jsx": "preserve", /* JSX 코드 생성 설정: 'preserve', 'react-native', 혹은 'react'. */
// "declaration": true, /* '.d.ts' 파일 생성 여부. */
// "declarationMap": true, /* 각 '.d.ts' 파일의 소스맵 생성 여부. */
// "sourceMap": true, /* '.map' 파일 생성 여부. */
// "outFile": "./", /* 단일 파일로 합쳐서 출력합니다. */
// "outDir": "./", /* 해당 디렉토리로 결과 구조를 보냅니다. */
// "rootDir": "./", /* 입력 파일의 루트 디렉토리(rootDir) 설정으로 --outDir로 결과 디렉토리 구조를 조작할 때 사용됩니다. */
// "composite": true, /* 프로젝트 컴파일 여부 */
// "tsBuildInfoFile": "./", /* 증분 컴파일 정보를 저장할 파일 */
// "removeComments": true, /* 주석 삭제 여부 */
// "noEmit": true, /* 결과 파일 내보낼지 여부 */
// "importHelpers": true, /* 'tslib'에서 헬퍼를 가져올 지 여부 */
// "downlevelIteration": true, /* 타겟이 'ES5', 'ES3'일 때에도 '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, /* strict mode로 분석하고 모든 소스 파일에 "use strict"를 추가할 지 여부 */
/* 추가적인 확인 */
// "noUnusedLocals": true, /* 사용되지 않은 지역 변수에 대한 에러보고 여부 */
// "noUnusedParameters": true, /* 사용되지 않은 파라미터에 대한 에러보고 여부 */
// "noImplicitReturns": true, /* 함수에서 코드의 모든 경로가 값을 반환하지 않을 시 에러보고 여부 */
// "noFallthroughCasesInSwitch": true, /* switch문에서 fallthrough 케이스에 대한 에러보고 여부 */
/* 모듈 해석 옵션 */
// "moduleResolution": "node", /* 모듈 해석 방법 설정: 'node' (Node.js) 혹은 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* non-absolute한 모듈 이름을 처리할 기준 디렉토리 */
// "paths": {}, /* 'baseUrl'를 기준으로 불러올 모듈의 위치를 재지정하는 엔트리 시리즈 */
// "rootDirs": [], /* 결합된 컨텐츠가 런타임에서의 프로젝트 구조를 나타내는 루트 폴더들의 목록 */
// "typeRoots": [], /* 타입 정의를 포함할 폴더 목록, 설정 안 할 시 기본적으로 ./node_modules/@types로 설정 */
// "types": [], /* 컴파일중 포함될 타입 정의 파일 목록 */
// "allowSyntheticDefaultImports": true, /* default export이 아닌 모듈에서도 default import가 가능하게 할 지 여부, 해당 설정은 코드 추출에 영향은 주지 않고, 타입확인에만 영향을 줍니다. */
"esModuleInterop": true, /* 모든 imports에 대한 namespace 생성을 통해 CommonJS와 ES Modules 간의 상호 운용성이 생기게할 지 여부, 'allowSyntheticDefaultImports'를 암시적으로 승인합니다. */
// "preserveSymlinks": true, /* symlik의 실제 경로를 처리하지 않을 지 여부 */
// "allowUmdGlobalAccess": true, /* UMD 전역을 모듈에서 접근할 수 있는 지 여부 */
/* 소스 맵 옵션 */
// "sourceRoot": "", /* 소스 위치 대신 디버거가 알아야 할 TypeScript 파일이 위치할 곳 */
// "mapRoot": "", /* 생성된 위치 대신 디버거가 알아야 할 맵 파일이 위치할 곳 */
// "inlineSourceMap": true, /* 분리된 파일을 가지고 있는 대신, 단일 파일을 소스 맵과 가지고 있을 지 여부 */
// "inlineSources": true, /* 소스맵과 나란히 소스를 단일 파일로 내보낼 지 여부, '--inlineSourceMap' 혹은 '--sourceMap'가 설정되어 있어야 한다. */
/* 실험적 옵션 */
// "experimentalDecorators": true, /* ES7의 decorators에 대한 실험적 지원 여부 */
// "emitDecoratorMetadata": true, /* decorator를 위한 타입 메타데이터를 내보내는 것에 대한 실험적 지원 여부 */
/* 추가적 옵션 */
"skipLibCheck": true, /* 정의 파일의 타입 확인을 건너 뛸 지 여부 */
"forceConsistentCasingInFileNames": true /* 같은 파일에 대한 일관되지 않은 참조를 허용하지 않을 지 여부 */
}
}
출처: https://geonlee.tistory.com/214 [빠리의 택시 운전사]
더 자세한 내용에 대해서는 타입스크립트 깃북 컴파일러옵션에 가면 옵션의 타입, 디폴트값, 설명이 모두 정리되어있으니 참고해서 추가하면 되겠다.
{
"compilerOptions": {
"target": "es6"
/* Modules */
"module": "ES2015",
"rootDir": "./src",
/* Emit */
"outDir": "./dist",
"removeComments": true,
"noEmitOnError": true,
/* Interop Constraints */
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
/* Type Checking */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true ,
"noFallthroughCasesInSwitch": true ,
"noUncheckedIndexedAccess": true,
/* Completeness */
"skipLibCheck": true
}
}
개발하면서 필요한 옵션들을 추가하고 삭제해서 최종적으로 작성된 옵션이다.
ts파일 작성이 완료되면 커맨드에 tsc
를 입력한다.
타입스크립트 모듈은 명령을 받고 ts파일을 우리가 설정한 outDir 폴더에 js파일로 변환하여 저장한다.
매번 저장하고 tsc하는 것이 귀찮다면 tsc -w
를 입력한다.
와치모드는 ts파일이 저장될 때 마다 자동으로 tsc명령어를 수행해준다.
nodejs의 nodemon과 비슷한 역할이다.
백엔드 프로젝트에선 typeorm을 init하면 tsconfig.json설정이 초기화 되므로 미리 설정하지 않을 것이다.
typeorm을 사용하지 않는다면 미리 설정해도 상관없다.
먼저 npm init
으로 package.json을 생성한다.
이제 백엔드에서 nodemon
과 tsc -w
를 함께 사용주기 위해서 concrrunetly
모듈을 함께 사용해보자
npm i --save-dev concurrently nodemon
그리고 package.json에서 “script”에 "start": "concurrently \"tsc -w\" \"nodemon dist/app.js\""
를 추가해준다.
이제부터 커맨드에 npm start
만으로 tsc -w와 nodemon을 동시에 사용할 수 있다.
js의 모듈인 express를 불러오면 express의 타입이 지정되어 있지 않아 any타입을 가지게 되고 ts에서는 오류가 발생한다.
이럴 땐 npm i --save-dev @types/express
를 통해서
이렇게 .d.ts파일을 받아오면 된다.
.d.ts는 해당 모듈의 타입에 대한 정보만 담아논 파일이다.
DefinitelyTyped 깃허브에 가면 사용하려는 모듈 대부분의 d.ts파일을 다운받을 수 있다.
직접 가서 다운받지 않고 @types/[module name]
을 npm install로 설치하면 된다.
helmet은 자체적으로 d.ts파일을 가지고 있어서 다시 설치할 필요가 없다.
오히려 설치하면 에러가 발생한다.
express의 error 파라미터는 타입이 없기 때문에 any로 받아준다.
{
"compilerOptions": {
"lib": ["es5", "es6", "ES2018"],
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"outDir": "./dist",
"rootDir": "./src",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"esModuleInterop": true,
"skipLibCheck": true,
"noEmitOnError": true,
"noUnusedLocals": true
}
}
typeorm을 init하면 tsconfig.json이 초기화된다.
나는 초기화된 tsconfig.json을 위와 같이 수정했다.
이것 역시 개발하면서 필요한 옵션들을 추가하고 삭제해서 최종적으로 작성된 옵션이다.