타입 스크립트는 어떤 것이든 구성 가능하며 모든 일반적인 자바스크립트 사용 패턴에 맞출 수 있다.
타입스크립트의 구성력은 다음을 통해 제공되는 100개 이상의 풍부한 구성 옵션에서부터 비롯된다.
- tsx에 전달된 명령줄(CLI)플래그
- 타입스크립트 구성 파일 TSConfig
13.1 tsc 옵션
tsc명령은 타입스크립트의 대부분 옵션을 —플래그로 사용할 수 있다.
예를들어 index.ts 파일에서 tsc를 실행할 때 index.js파일 생성을 건너 뛰려면(타입 검사만 실행) —noEmit 플래그를 전달한다.
tsc index.ts --noEmit
tsc —help를 실행해 일반적으로 사용하는 CLI플래그 목록을 가져올 수 있다. (전체는 tsc —all)
13.1.1 pretty 모드
tsc CLI는 색상과 간격의 스타일을 통해 가독성을 높히는 pretty 모드를 지원한다.
여러 가지 색이 없는 더 압축된 CLI 출력을 선호하면 tsc —pretty false플래그를 사용하여 제한할 수 있다.
13.1.2 watch 모드
tsc -w 나 tsc—watch를 사용하면 모든 오류를 실시간으로 업데이트하여 일일이 실행하지않고 확인할 수 있게된다. 대규모 변경 작업을할때 검출되는 오류를 한줄씩 지워나가면서 작업하는데 유용하다.
13.2 TSConfig 파일
모든 파일 이름과 구성 옵션을 항상 tsc에 제공하는 대신, 대부분의 구성 옵션을 디렉터리의 tsconfig.json(TSConfig)파일에 구체적으로 명시할 수 있다.
tsconfig.json의 존재는 해당 디렉터리가 타입스크립트 프로젝트의 루트임을 나타낸다.
디렉터리에서 tsc를 실행하면 해당 tsconfig.json 파일의 모든 구성 옵션을 읽는다.
만약 루트 경로가 아니라면 tsc -p path/to/tsconfig.json과같이 -p나 -project 플래그사용하여 실행한다.
VS Code같은 IDE는 IntelliSencs 기능을 사용할때 TSConfig의 구성을 따름으로 가능하면 타입스크립트 프로젝트내에서 TSConfig파일을 사용하길 권장한다.
13.2.1 tsc —init
tsc명령줄에는 tsconfig.json파일을 생성하기 위한 —init명령이 포함되어 있다.
새로 생성된 TSConfig파일에는 공식문서의 링크와 사용을 간단하게 알려주는 한줄 주석이 포함되어있다.
13.2.2 CLI vs config
CLI와 TSConfig파일에서 사용 가능한 대부분의 옵션은 다음 두가지 범주 중 하나로 분류된다.
- 컴파일러: 포함된 각 파일이 타입스크립트에 따라 컴파일되거나 타입을 확인하는 방법
- 파일: 타입스크립트가 실행될 파일과 실행되지 않은 파일
프로젝트 레퍼런스와 같은 다른 설정은 TSConfig파일에서만 사용할 수 있다.
13.3 파일 포함
기본적으로 tsc는 현재 디렉터리와 하위 디렉터리에 있는 숨겨지지 않은 모든 .ts파일에서 실행되고, 숨겨진 디렉터리와 node_modules 디렉터리는 무시된다
- 숨겨진 디렉터리란? 일반적으로 .gitignore, .vscode같이 접두사(.)가 붙은 파일
13.3.1 include
파일을 포함하는 가장 흔한 방법으로 tsconfig.json의 최상위 ‘include’속성을 사용한다. include속성에 타입스크립트 컴파일에 포함할 디렉터리와 파일을 설명하는 문자열 배열을 명시한다.
예를들어 다음 구성 파일은 tsconfig.json과 관련된 src/ 디렉터리 안의 모든 타입스크립트 소스 파일을 재귀적으로 포함한다.
// tsconfig
{
"include":["src"]
}
좀더 세밀하게 제어하기위해 글로브 와일드카드가 허용된다.
- *: 0개 이상의 문자와 일치한다(디렉터리 구분자 제외)
- ?: 하나의 문자와 일치한다(디렉터리 구분자 제외)
- **/: 모든 레벨에 중첩된 모든 디렉터리와 일치한다.
다음 구성 파일은 typings/ 하위의 중첩된 디렉터리의 .d.ts파일과 확장자 앞의 파일명에 적어도 두 개 이상의 문자를 가진 src/ 하위의 파일만 허용한다.
{
"include": [
"typings/**/*.d.ts",
"src/**/*??.*"
]
}
대부분의 프로젝트는 [”src”]로 충분하다.
13.3.2 exclude
include 파일 목록에 타입스크립트로 컴파일할 수 없는 파일이 포함되는 경우가 있다.
타입스크립트는 TSConfig파일의 최상위 “exclude” 속성에 경로를 지정하고 include에서 경로를 생략한다.
include처럼 타입스크립트 컴파일에서 제외할 디렉터리와 파일을 설명하는 문자열 배열이 허용된다.
적용되는 파일을 설명하는 문자열 배열은 include와 동일하다.
아래의 구성파일은 중첩된 /external 디렉터리와 node_modules 디렉터리 내의 모든 파일은 제외하고 src/ 내의 모든 파일을 포함한다.
{
"exclude":["**/external","node_modules"],
"include": ["src"]
}
기본적으로 exclude에는 컴파일된 외부 라이브러리 파일에 대해 타입스크립트 컴파일러가 실행되지 않도록 [”node_modules”, ”bower_components” ,”jspm_packages”]가 포함된다.
대부분은 npm을 사용함으로 “node_modules”만 설정해주면 된다.
13.4 대체 확장자
타입스크립트는 기본적으로 확장자가 .ts인 모든 파일을 읽을 수 있다. 그러나 리액트와같은 UI 라이브러리를 위한 JSX구문처럼 확장자가 다른 파일을 읽을 수 있어야 한다.
13.4.1 JSX구문
<Comment />같은 JSX구문은 프리액트와 리액트 같은 UI라이브러리에서 자주 사용한다. JSX구문은 기술적으로 자바스크립트가아닌, 타입 스크립트의 타입 정의와 마찬가지로 자바스크립트로 컴파일되는 자바스크립트 구문의 확장이다.
파일에서 JSX구문을 사용하기위해선 다음 두 가지를 수행해야한다.
- TSConfig에서 “jsx”컴파일러 옵션을 활성화한다.
- .tsx확장자로 파일의 이름을 지정한다.
jsx
타입스크립트가 .tsx파일에 대한 자바스크립트 코드를 내보내는 방법은 “jsx”컴파일러 옵션에 사용되는 값으로 결정된다.
jsx에 대한 값은 tsc CLI 또는 TSConfig파일에 제공한다.
tsc --jsx preserve
{
"compilerOptions": {
"jsx": "preserve"
}
}
바벨과 같은 별도의 도구로 코드를 변환하는 것처럼 타입스크립트의 내장된 트랜스파일러를 직접적으로 사용 하지 않는 경우에는 “jsx” 옵션을 사용할 수 있다.(타입스크립트는 타입 검사만 진행) next.js,리믹스와 같은 최신 프레임워크를 사용하면 타입스크립트의 내장 트랜스파일러를 직접 구성할 필요가 없다.
.tsx 파일의 제네릭 화살표 함수
.tsx파일에서 화살표 함수에 대한 타입 인수<T>를 작성하려고 하면 T요소의 시작 태그에 대한 종료 태그가 없기 때문에 구문 오류가 발생한다.
const f1 = <T>(input:T) => input;
//error: JSX element 'T' has no corresponding closing tag.ts(17008)
이런 모호성을 해결하기 위해 타입 인수에 =unknown 제약 조건을 추가할 수 있다. 타입 인수 기본값은 unkonwn타입 이므로 코드 동작이 전혀 변경되지 않는다. 단지 JSX요소가 아닌 타입 인수를 읽도록 타입스크립트에 지시할뿐이다.
const f1 = <T = unknown>(input:T) => input; // OK
13.4.2 resolveJsonModule
타입스크립트는 resolveJsonModule 컴파일러 옵션을 true로 설정하면 .json파일을 읽을 수 있다. 이렇게하면 .json파일을 마치 객체를 내보내는 .ts파일인 것처럼 가져오고 해당 객체의 타입을 const 변수인 것처럼 유추한다.
객체가 포함된 JSON파일이라면 구조 분해 가져오기를 사용할 수 있고 array또는 number같은 다른 리터럴 타입을 포함한 JSON파일이라면 import 구문으로 *을 사용한다.
13.5 자바스크립트로 내보내기
바벨 같은 전용 컴파일러 도구의 등장으로 일부 프로젝트에서는 타입스크립트의 역할이 타입 검사만으로 축소되었지만, 타입스크립트 구문을자바스크립트로 컴파일 하기 위해 여전히 타입스크립트에 의존하고 있는 프로젝트도 많다.
타입스크립트에 단일 의존성을 갖고 tsc명령을 사용해 자바스크립트를 출력하는 작업은 매우 유용하다.
13.5.1 outDir
기본적으로 타입스크립트 출력파일은 해당 소스코드 파일과 동일한 위치에 생성된다.
outDir 컴파일러 옵션을 사용하면 출력 파일의 루트 디렉터리를 다르게 지정할 수 있다.
tsc --outDir dist
위 명령어는 dist/ 폴더 내에 출력파일을 생성하게 한다.
13.5.2 target
타입스크립트는 ES3(1999년경)과 같은 오래된 환경에서 실행할 수 있는 자바스크립트 출력 파일을 생성할 수 있다.
target컴파일러 옵션은 자바스크립트 코드 구문을 지원하기위해 어느 버전까지 변환해야 하는지를 지정하는옵션이다.
target을 지정하지 않으면 이전 버전과의 호환을 위해 기본적으로 “es3”이 지정된다.
tsc —init은 기본적으로 “es16”을 지정하도록 설정되어있다.
오래된 환경에서 최신 자바스크립트 기능을 지원하려면 더 많은 자바스크립트 코드를 생성해야하므로, 파일 크기가 조금 더 커지고 런타임 성능이 조금 저하되기때문에 무조건 낮은 버전을 호환하는게 좋지않을 수 있다.
- 22년기준 0.1% 이상을 서비스하는 브라우저의 최소 버전은 2019와 거의 모든 2020~2021을 지원한다. 또한 LTS지원 버전의 Node.js는 모든 2021을 지원한다. 따라서 target속성을 적어도“es2019” 이상으로 지정하지 않을 이유가 없다.
13.5.3 내보내기 선언
대부분의 패키지는 타입스크립트의 declaration 컴파일러 옵션을 사용해 소스 파일에서 .d.ts출력 파일을 내보낸다.
{
"compilerOptions": {
"declaration": true
}
}
.d.ts 출력파일은 outDir 옵션에따라 .js 파일과 동일한 출력 규칙에 따라 내보내진다.
fruits/apple.ts가 있는 디렉터리에서 tsc-declaration을 실행하면 출력.js파일과 함께 fruits/apple.d.ts출력 선언 파일이 생성된다.
emitDeclarationOnly
이 옵션은 타입스크립트가 .js와 .jsx파일 없이 선언 파일만 내보내도록 지시한다. 이는 외부 도구를 사용해 출력 자바스크립트를 생성하지만 여전히 타입스크립트를 사용해 출력 선언 파일을 생성하려는 프로젝트에 유용하다.
emitDeclarationOnly가 활성화된경우 declaration 또는 composite 옵션이 활성화되어야한다.
13.5.4 소스 맵
소스맵은 출력 파일의 내용이 원본 소스 파일과 어떻게 일치하는지에 대한 설명이다.
소스맵은 디버거 같은 개발자 도구에서 원본 소스 파일 내용을 볼 수 있도록 설정한다.
sourceMap
sourceMap 옵션을 활성화하면 .js 또는 .jsx 출력파일과 함께 .js.map 또는 .jsx.map소스 맵을 출력할 수 있다.
declarationMap
declarationMap옵션을 사용하면 .d.ts 선언 파일에 대한 소스 맵을 생성할 수도 있다. .d.ts.map 파일로 생성된다. declarationMap를 활성화하면 VS Code 같은 IDE에서 [Go to Definition]기능으로 원본 소스 파일로 이동할 수 있다.( 이 장 마지막에서 볼 프로젝트 레퍼런스 작업에 유용하다)
13.5.5 noEmit
noEmit옵션을 활성화하면 다른 도구를 통해 컴파일, 자바스크립트를 출력하게 지시하고 타입스크립트는 오직 타입검사기로만 동작하게 된다.
어떤한 파일도 생성하지않고 오직 구문 또는 타입 오류만을 보고하게된다.
13.6 타입 검사
타입스크립트 구성 옵션은 타입 검사기를 제어한다.
13.6.1 lib
타입스크립트가 런타임 환경에 있다고 가정하는 전역 API는 lib컴파일러 옵션으로 구성 할 수 있다.
lib설정을 변경하는 유일한 이유는 브라우저에서 실행되지 않는 프로젝트를 설정하기 위해 lib설정에 기본적으로 포함되어있는 dom을 제거하기 위함이다.
또는 최신 자바스크립트 API를 지원하기 위해 폴리필을 사용하는 프로젝트에서 lib 컴파일러 옵션을 사용해 dom 과 ECMA스크립트 특정 버전을 포함할 수 있다.
올바른 런타임 폴리필을 모두 제공하지 않는 상태에서 lib을 수정하지않도록 주의하자.
ES2020까지만 지원하는 플랫폼에서 프로젝트의 lib가 “es2021”로 설정되었다면 프로젝트에서는 타입 검사 오류가 없을 수 있지만 String.replaceAll과 같이 ES2021이상에 정의된 API를 사용하려고하면 런타임 오류가 발생할 수 있다.
lib 컴파일러 옵션은 내장된 언어 API를 나타내는 데 사용하고, target컴파일러 옵션은 존재하는 구문을 나타내는 데 사용한다고 생각하자
13.6.2 skipLibCheck
소스 코드에 명시적으로 포함되지 않은 선언 파일에서 타입검사를 생략하도록 지시하는 컴파일 옵션.
공유된 라이브러리의 정의가 서로 다르고 충돌할 수 있는 패키지 의존성을 많이 사용하는 애플리케이션에서 유용하다 이는 타입 검사 일부를 건너뛰는 작업으로 성능을 개선키므로 대부분의 프로젝트에서 활성화 시키는것이 좋다.
13.6.3 엄격모드
타입스크립트의 타입 검사 컴파일러 옵션 대부분은 엄격모드로 그룹화 된다.
엄격모드의 기본값은 false다.
noImplicitAny와 stringNullChecks는 타입 안전 코드를 작성하는데 특히 유용하다.
noImplicitAny
암시적으로 타입이 any로 대체될때 타입검사기가 오류를 발생하도록 지시하는 옵션
strictBindCallApply
초기 타입스크립트에는 Function.apply, Function.bind, Function.call 함수 유틸리티를 나타낼 만큼 충분한 타입 시스템이 없어 any타입을 사용했지만 이 옵션을 활성화하면 타입을 지원해준다.
strictFunctionTypes
함수 매개변수의 타입을 좀더 엄격하게 관리해주는 옵션.
매개변수가 옵셔널 매개변수를 갖는 함수인 함수에 단일 타입의 매개변수를 갖는 함수를 인수로 전달하면 기본 타입검사에서는 허용하지만, 이옵션을 활성화하면 오류가 발생한다(매개변수 타입이 옵셔널로 완전히 동일해야 오류가 발생하지 않는다)
strictNullChecks
기본적으로 모든 코드의 타입에 null | undefined 타입이 허용되지만, 이옵션을 활성화하면 특정 타입에 null | undefined타입을 할당하면 오류를 발생한다.(타입스크립트의 모범사례는 이 옵션을 활성화시키는것이다)
strictPropertyInitialization
클래스의 초기화가 없고 생성자에 확실하게 할당되지 않은 클래스 속성에 타입오류를 발생시키는 옵션(타입스크립트의 모범사례는 이 옵션을 활성화시키는것이다)
useUnknownInCatchVariables
타입스크립트의 기본 catch절 error 타입을 unknown으로 변경하는 옵션.(타입스크립트의 모범사례는 이 옵션을 활성화시키는것이다) - 기본타입 검사기에서는 any이며, 이를 억지로 명시적 어셔션등의 방법으로 오류가 특정 타입이 될 수 있는 것으로 가정하는 것이 언제나 안전하지는 않기 때문.
13.7 모듈
13.7.1 module
타입스크립트는 어떤 모듈 시스템으로 변환된 코드를 사용할지 결정하기 위해 module 컴파일러 옵션을 제공한다.
예를들어 ECMA스크립트 모듈로 작성된 소스코드를 아래와 같은 명령어로 CommonJS모듈로 출력하도록지시할 수 있다.
tsc --module commonjs
TSConfig에서도 가능.
{
"compilerOptions" : {
"module": "commonjs",
}
}
target컴파일러 옵션이 “es3”나 “es5”인 경우 module컴파일러 옵션의 기본값은 “commonjs”이고, 그렇지않으면 ECMA스크립트 모듈로 출력하도록 지정하기위해 “es2015”로 기본 설정된다.
13.7.2 moduleResolution
모듈 해석(module resolution)이란 import에서 가져온 경로가 module에 매핑되는 과정을 의미한다.
이때 타입스크립트가 선호하는 로직은 두 가지중 하나이다.
- node: 기존 Node.js와 같은 CommonJS 리졸버 에서 사용하는 동작
- nodenext: ECMA스크립트 모듈에 대해 지정된 동작에 맞게 조정
{
"compilerOptions": {
"moduleResolution": "nodenext"
}
}
두 값은 유사하게 동작하여 차이가 거의 없다.
13.7.3 CommonJS와의 상호 운용성
CommonJS와 ECMA스크립트 모듈 내보내기 및 가져오기형식 비교
타입스크립트에서는 두 방식간을 상호운용할 수 있는 컴파일 옵션을 제공한다.
esModuleInterop
이 옵션은 위 표에서 ECMA스크립트 모듈이 기본 또는 네임스페이스 가져오기에 대한 ECMA스크립트 방식을 따르지 않아도 모듈을 가져올 수 있도록 한다.(호환을 위한 로직을 내부적으로 추가하여가능하게함)
allowSyntheticDefaultImports
CommonJS 네임스페이스 내보내기 파일을 ECMA스크립트의 기본 가져오기로 사용할 수 있게 해주는 옵션.
이 옵션은 다음중 하나가 true인 경우에만 true로 설정된다.
- module옵션이 “system”인 경우.(오래되고 거의 사용하지 않는 모듈 형식이다)
- esModuleInterop이 true이고 module이 “es2015” 또는 “esnext”와 같은 ECMA 스크립트 모듈 형식이 아닌 경우
13.7.4 isolatedModules
프로젝트에서 타입스크립트가 아닌 다른 도구를 사용해 자바스크립트로 변환하는 경우에는 isolationModules를 활성화하는것이 좋다.
13.8 자바스크립트
타입스크립트는 .js, .jsx확장자를 가진 파일을 무시하지만, allowJs와 checkJs 컴파일러 옵션을 사용하면 자바스크립트 파일을 읽고, 컴파일하고, 제한된 기능이지만 타입 검사도 할 수 있다.
- 기존 자바스크립트 프로젝트에 타입스크립트를 적용할때의 일반적인 전략으로, 타입스크립트로 변환된 몇개의 파일에서부터 점점 늘려가며 전환하는방식이 있다.
13.8.1 allowJs
자바스크립트파일에 선언된 구문을 타입스크립트 파일에서 타입 검사를 하도록 허용하는 옵션.
// index.ts
import { value } from "./values";
console.log(`${value.toUpperCase()}`);
// index.js
export const value = "test String";
기본적으로 allowJs를 활성화시키지않으면, .ts파일에서 .js파일을 불러올때 any타입이 되거나 모듈자체를 불러올수 없게되지만, allowJs를 활성화하면 위 코드를 기준으로 value가 string임을 검사한다.
13.8.2 checkJs
자바스크립트 파일도 타입검사가 가능하게 해주는 옵션
- checkJs가 동작하려면 allowJs 옵션이 true로 설정되어 있어야함
- .js와 .jsx파일에서 타입 검사기 활성화하기
@ts-check
파일 상단에 // @ts-check 주석을 사용해 파일별로 checkJs를 활성화 할 수 있다.
13.8.3 JSDoc 지원
자바스크립트에는 타입스크립트만큼의 타입구문이 없기 때문에 자바스크립트 파일에 선언된 값의 타입은 명확하지 않을 수 있다. ex. 인터페이스
allowJs와 checkJs가 활성화되면 타입스크립트는 코드의 모든 JSDoc정의를 실제로 인식한다.
13.9 구성 확장
13.9.1 extends
TSConfig는 extends 옵션을통해 확장할 수 있다.
클래스의 extends키워드와 유사하게 동작하고, 확장할 tsconfig.json파일에대해 tsconfig.base.json 파일을 생성한다.
//tsconfig.base.json
{
"compilerOptions" :{
"strict": true
}
}
//pakages/core/tsconfig.json
{
"extends": "../../tsconfig.base.json",
"includes": ["src"]
}
13.9.2 구성 베이스
처음부터 —init 제안을 하는 대신, 특정 런타임 환경에 맞는 미리 만들어진 베이스TSConfig 파일로 시작할 수 있다.
- @tsconfig/recommended
- @tsconfig/node16
등 @tsconfig/ 아래의 npm 패키지 레지스트리에서 사용할 수 있다.
https://github.com/tsconfig/bases
13.10 프로젝트 레퍼런스
대규모 프로젝트에서는 프로젝트의 서로 다른 영역에 서로 다른 구성 파일을 사용 하는 것이 유용하다.
타입스크립트에서는 여러 개의 프로젝트를 함께 빌드하는 프로젝트 레퍼런스 시스템을 정의할 수 있다.
이점
- 특정 코드 영역에 대해 다른 컴파일러 옵션을 지정할 수 있다.
- 타입스크립트는 개별 프로젝트에 대한 빌드 출력을 캐시할 수 있으므로 종종 대규모 프로젝트의 빌드 시간이 빨라진다.
- 코드의 개별 영역을 구조화하는데 유용한 의존성 트리(특정 프로젝트가 다른 특정 프로젝트에서만 파일을 가져오게 허용)를 실행한다.
→ 프로젝트 레퍼런스는 모노레포, 모듈식 컴포넌트 시스템처럼 별개의 코드 영역 여러개로 구성된 대규모 프로젝트에서 사용한다.
13.10.1 composite
빌드 입력과 비교해 빌드 출력이 최신 상태인지 여부를 확인하고 싶을때 활성화시키는 옵션
13.10.2 references
core/디렉터리를 입력으로 참조하도록 shell/ 디렉터리를 설정한다.
// shell/tsconfig.json
{
"references" : [
{"path": "../core"}
]
}
13.10.3 빌드 모드
프로젝트 레퍼런스를 사용하도록 설정되면 빌드모드에서 -b 또는 —b CLI 플래그를 통해 tsc를 사용할 수 있습니다. 빌드모드는 tsc를 프로젝트 빌드 코디네이터같은 것으로 향상시킨다.
타입스크립트의 빌드 모드는 TSConfig가 제공될때 다음 내용을 수행한다.
- TSConfig의 참조된 프로젝트를 찾는다.
- 최신 상태인지 감지한다.
- 오래된 프로젝트를 올바른 순서로 빌드한다.
- 제공된 TSConfig 또는 TSConfig의 의존성이 변경된 경우 빌드한다.
→ 타입스크립트 빌드 모드 기능은 최신 프로젝트를 다시 빌드하는 것을 건너뛰도록 해 빌드 성능을 크게 향상 시킨다.
코디네이터 구성
저장소에서 타입스크립트 프로젝트 레퍼런스를 설정하는 편리한 방법은 빈 파일 배열과 저장소의 모든 프로젝트 레퍼런스에 대한 레퍼런스를 사용해 최상위 레벨의 tsconfig.json을 설정하는 것이다.
최상위 TSConfig는 타입스크립트가 파일 자체를 빌드하도록 지시하지 않는다.
대신 필요에따라 참조된 프로젝트를 빌드하도록 타입스크립트에 알리려는 역할만한다.
다음 tsconfig.json은 저장소의 packages/core와 packages/sheel 프로젝트를 빌드하는 것을 나타낸다.
//tsconfig.json
{
"files": [],
"references": [
{"path": "./packages/core"},
{"path": "./packages/shell"}
]
}
타입 스크립트는 어떤 것이든 구성 가능하며 모든 일반적인 자바스크립트 사용 패턴에 맞출 수 있다.
타입스크립트의 구성력은 다음을 통해 제공되는 100개 이상의 풍부한 구성 옵션에서부터 비롯된다.
- tsx에 전달된 명령줄(CLI)플래그
- 타입스크립트 구성 파일 TSConfig
13.1 tsc 옵션
tsc명령은 타입스크립트의 대부분 옵션을 —플래그로 사용할 수 있다.
예를들어 index.ts 파일에서 tsc를 실행할 때 index.js파일 생성을 건너 뛰려면(타입 검사만 실행) —noEmit 플래그를 전달한다.
tsc index.ts --noEmit
tsc —help를 실행해 일반적으로 사용하는 CLI플래그 목록을 가져올 수 있다. (전체는 tsc —all)
13.1.1 pretty 모드
tsc CLI는 색상과 간격의 스타일을 통해 가독성을 높히는 pretty 모드를 지원한다.
여러 가지 색이 없는 더 압축된 CLI 출력을 선호하면 tsc —pretty false플래그를 사용하여 제한할 수 있다.
13.1.2 watch 모드
tsc -w 나 tsc—watch를 사용하면 모든 오류를 실시간으로 업데이트하여 일일이 실행하지않고 확인할 수 있게된다. 대규모 변경 작업을할때 검출되는 오류를 한줄씩 지워나가면서 작업하는데 유용하다.
13.2 TSConfig 파일
모든 파일 이름과 구성 옵션을 항상 tsc에 제공하는 대신, 대부분의 구성 옵션을 디렉터리의 tsconfig.json(TSConfig)파일에 구체적으로 명시할 수 있다.
tsconfig.json의 존재는 해당 디렉터리가 타입스크립트 프로젝트의 루트임을 나타낸다.
디렉터리에서 tsc를 실행하면 해당 tsconfig.json 파일의 모든 구성 옵션을 읽는다.
만약 루트 경로가 아니라면 tsc -p path/to/tsconfig.json과같이 -p나 -project 플래그사용하여 실행한다.
VS Code같은 IDE는 IntelliSencs 기능을 사용할때 TSConfig의 구성을 따름으로 가능하면 타입스크립트 프로젝트내에서 TSConfig파일을 사용하길 권장한다.
13.2.1 tsc —init
tsc명령줄에는 tsconfig.json파일을 생성하기 위한 —init명령이 포함되어 있다.
새로 생성된 TSConfig파일에는 공식문서의 링크와 사용을 간단하게 알려주는 한줄 주석이 포함되어있다.
13.2.2 CLI vs config
CLI와 TSConfig파일에서 사용 가능한 대부분의 옵션은 다음 두가지 범주 중 하나로 분류된다.
- 컴파일러: 포함된 각 파일이 타입스크립트에 따라 컴파일되거나 타입을 확인하는 방법
- 파일: 타입스크립트가 실행될 파일과 실행되지 않은 파일
프로젝트 레퍼런스와 같은 다른 설정은 TSConfig파일에서만 사용할 수 있다.
13.3 파일 포함
기본적으로 tsc는 현재 디렉터리와 하위 디렉터리에 있는 숨겨지지 않은 모든 .ts파일에서 실행되고, 숨겨진 디렉터리와 node_modules 디렉터리는 무시된다
- 숨겨진 디렉터리란? 일반적으로 .gitignore, .vscode같이 접두사(.)가 붙은 파일
13.3.1 include
파일을 포함하는 가장 흔한 방법으로 tsconfig.json의 최상위 ‘include’속성을 사용한다. include속성에 타입스크립트 컴파일에 포함할 디렉터리와 파일을 설명하는 문자열 배열을 명시한다.
예를들어 다음 구성 파일은 tsconfig.json과 관련된 src/ 디렉터리 안의 모든 타입스크립트 소스 파일을 재귀적으로 포함한다.
// tsconfig
{
"include":["src"]
}
좀더 세밀하게 제어하기위해 글로브 와일드카드가 허용된다.
- *: 0개 이상의 문자와 일치한다(디렉터리 구분자 제외)
- ?: 하나의 문자와 일치한다(디렉터리 구분자 제외)
- **/: 모든 레벨에 중첩된 모든 디렉터리와 일치한다.
다음 구성 파일은 typings/ 하위의 중첩된 디렉터리의 .d.ts파일과 확장자 앞의 파일명에 적어도 두 개 이상의 문자를 가진 src/ 하위의 파일만 허용한다.
{
"include": [
"typings/**/*.d.ts",
"src/**/*??.*"
]
}
대부분의 프로젝트는 [”src”]로 충분하다.
13.3.2 exclude
include 파일 목록에 타입스크립트로 컴파일할 수 없는 파일이 포함되는 경우가 있다.
타입스크립트는 TSConfig파일의 최상위 “exclude” 속성에 경로를 지정하고 include에서 경로를 생략한다.
include처럼 타입스크립트 컴파일에서 제외할 디렉터리와 파일을 설명하는 문자열 배열이 허용된다.
적용되는 파일을 설명하는 문자열 배열은 include와 동일하다.
아래의 구성파일은 중첩된 /external 디렉터리와 node_modules 디렉터리 내의 모든 파일은 제외하고 src/ 내의 모든 파일을 포함한다.
{
"exclude":["**/external","node_modules"],
"include": ["src"]
}
기본적으로 exclude에는 컴파일된 외부 라이브러리 파일에 대해 타입스크립트 컴파일러가 실행되지 않도록 [”node_modules”, ”bower_components” ,”jspm_packages”]가 포함된다.
대부분은 npm을 사용함으로 “node_modules”만 설정해주면 된다.
13.4 대체 확장자
타입스크립트는 기본적으로 확장자가 .ts인 모든 파일을 읽을 수 있다. 그러나 리액트와같은 UI 라이브러리를 위한 JSX구문처럼 확장자가 다른 파일을 읽을 수 있어야 한다.
13.4.1 JSX구문
<Comment />같은 JSX구문은 프리액트와 리액트 같은 UI라이브러리에서 자주 사용한다. JSX구문은 기술적으로 자바스크립트가아닌, 타입 스크립트의 타입 정의와 마찬가지로 자바스크립트로 컴파일되는 자바스크립트 구문의 확장이다.
파일에서 JSX구문을 사용하기위해선 다음 두 가지를 수행해야한다.
- TSConfig에서 “jsx”컴파일러 옵션을 활성화한다.
- .tsx확장자로 파일의 이름을 지정한다.
jsx
타입스크립트가 .tsx파일에 대한 자바스크립트 코드를 내보내는 방법은 “jsx”컴파일러 옵션에 사용되는 값으로 결정된다.
jsx에 대한 값은 tsc CLI 또는 TSConfig파일에 제공한다.
tsc --jsx preserve
{
"compilerOptions": {
"jsx": "preserve"
}
}
바벨과 같은 별도의 도구로 코드를 변환하는 것처럼 타입스크립트의 내장된 트랜스파일러를 직접적으로 사용 하지 않는 경우에는 “jsx” 옵션을 사용할 수 있다.(타입스크립트는 타입 검사만 진행) next.js,리믹스와 같은 최신 프레임워크를 사용하면 타입스크립트의 내장 트랜스파일러를 직접 구성할 필요가 없다.
.tsx 파일의 제네릭 화살표 함수
.tsx파일에서 화살표 함수에 대한 타입 인수<T>를 작성하려고 하면 T요소의 시작 태그에 대한 종료 태그가 없기 때문에 구문 오류가 발생한다.
const f1 = <T>(input:T) => input;
//error: JSX element 'T' has no corresponding closing tag.ts(17008)
이런 모호성을 해결하기 위해 타입 인수에 =unknown 제약 조건을 추가할 수 있다. 타입 인수 기본값은 unkonwn타입 이므로 코드 동작이 전혀 변경되지 않는다. 단지 JSX요소가 아닌 타입 인수를 읽도록 타입스크립트에 지시할뿐이다.
const f1 = <T = unknown>(input:T) => input; // OK
13.4.2 resolveJsonModule
타입스크립트는 resolveJsonModule 컴파일러 옵션을 true로 설정하면 .json파일을 읽을 수 있다. 이렇게하면 .json파일을 마치 객체를 내보내는 .ts파일인 것처럼 가져오고 해당 객체의 타입을 const 변수인 것처럼 유추한다.
객체가 포함된 JSON파일이라면 구조 분해 가져오기를 사용할 수 있고 array또는 number같은 다른 리터럴 타입을 포함한 JSON파일이라면 import 구문으로 *을 사용한다.
13.5 자바스크립트로 내보내기
바벨 같은 전용 컴파일러 도구의 등장으로 일부 프로젝트에서는 타입스크립트의 역할이 타입 검사만으로 축소되었지만, 타입스크립트 구문을자바스크립트로 컴파일 하기 위해 여전히 타입스크립트에 의존하고 있는 프로젝트도 많다.
타입스크립트에 단일 의존성을 갖고 tsc명령을 사용해 자바스크립트를 출력하는 작업은 매우 유용하다.
13.5.1 outDir
기본적으로 타입스크립트 출력파일은 해당 소스코드 파일과 동일한 위치에 생성된다.
outDir 컴파일러 옵션을 사용하면 출력 파일의 루트 디렉터리를 다르게 지정할 수 있다.
tsc --outDir dist
위 명령어는 dist/ 폴더 내에 출력파일을 생성하게 한다.
13.5.2 target
타입스크립트는 ES3(1999년경)과 같은 오래된 환경에서 실행할 수 있는 자바스크립트 출력 파일을 생성할 수 있다.
target컴파일러 옵션은 자바스크립트 코드 구문을 지원하기위해 어느 버전까지 변환해야 하는지를 지정하는옵션이다.
target을 지정하지 않으면 이전 버전과의 호환을 위해 기본적으로 “es3”이 지정된다.
tsc —init은 기본적으로 “es16”을 지정하도록 설정되어있다.
오래된 환경에서 최신 자바스크립트 기능을 지원하려면 더 많은 자바스크립트 코드를 생성해야하므로, 파일 크기가 조금 더 커지고 런타임 성능이 조금 저하되기때문에 무조건 낮은 버전을 호환하는게 좋지않을 수 있다.
- 22년기준 0.1% 이상을 서비스하는 브라우저의 최소 버전은 2019와 거의 모든 2020~2021을 지원한다. 또한 LTS지원 버전의 Node.js는 모든 2021을 지원한다. 따라서 target속성을 적어도“es2019” 이상으로 지정하지 않을 이유가 없다.
13.5.3 내보내기 선언
대부분의 패키지는 타입스크립트의 declaration 컴파일러 옵션을 사용해 소스 파일에서 .d.ts출력 파일을 내보낸다.
{
"compilerOptions": {
"declaration": true
}
}
.d.ts 출력파일은 outDir 옵션에따라 .js 파일과 동일한 출력 규칙에 따라 내보내진다.
fruits/apple.ts가 있는 디렉터리에서 tsc-declaration을 실행하면 출력.js파일과 함께 fruits/apple.d.ts출력 선언 파일이 생성된다.
emitDeclarationOnly
이 옵션은 타입스크립트가 .js와 .jsx파일 없이 선언 파일만 내보내도록 지시한다. 이는 외부 도구를 사용해 출력 자바스크립트를 생성하지만 여전히 타입스크립트를 사용해 출력 선언 파일을 생성하려는 프로젝트에 유용하다.
emitDeclarationOnly가 활성화된경우 declaration 또는 composite 옵션이 활성화되어야한다.
13.5.4 소스 맵
소스맵은 출력 파일의 내용이 원본 소스 파일과 어떻게 일치하는지에 대한 설명이다.
소스맵은 디버거 같은 개발자 도구에서 원본 소스 파일 내용을 볼 수 있도록 설정한다.
sourceMap
sourceMap 옵션을 활성화하면 .js 또는 .jsx 출력파일과 함께 .js.map 또는 .jsx.map소스 맵을 출력할 수 있다.
declarationMap
declarationMap옵션을 사용하면 .d.ts 선언 파일에 대한 소스 맵을 생성할 수도 있다. .d.ts.map 파일로 생성된다. declarationMap를 활성화하면 VS Code 같은 IDE에서 [Go to Definition]기능으로 원본 소스 파일로 이동할 수 있다.( 이 장 마지막에서 볼 프로젝트 레퍼런스 작업에 유용하다)
13.5.5 noEmit
noEmit옵션을 활성화하면 다른 도구를 통해 컴파일, 자바스크립트를 출력하게 지시하고 타입스크립트는 오직 타입검사기로만 동작하게 된다.
어떤한 파일도 생성하지않고 오직 구문 또는 타입 오류만을 보고하게된다.
13.6 타입 검사
타입스크립트 구성 옵션은 타입 검사기를 제어한다.
13.6.1 lib
타입스크립트가 런타임 환경에 있다고 가정하는 전역 API는 lib컴파일러 옵션으로 구성 할 수 있다.
lib설정을 변경하는 유일한 이유는 브라우저에서 실행되지 않는 프로젝트를 설정하기 위해 lib설정에 기본적으로 포함되어있는 dom을 제거하기 위함이다.
또는 최신 자바스크립트 API를 지원하기 위해 폴리필을 사용하는 프로젝트에서 lib 컴파일러 옵션을 사용해 dom 과 ECMA스크립트 특정 버전을 포함할 수 있다.
올바른 런타임 폴리필을 모두 제공하지 않는 상태에서 lib을 수정하지않도록 주의하자.
ES2020까지만 지원하는 플랫폼에서 프로젝트의 lib가 “es2021”로 설정되었다면 프로젝트에서는 타입 검사 오류가 없을 수 있지만 String.replaceAll과 같이 ES2021이상에 정의된 API를 사용하려고하면 런타임 오류가 발생할 수 있다.
lib 컴파일러 옵션은 내장된 언어 API를 나타내는 데 사용하고, target컴파일러 옵션은 존재하는 구문을 나타내는 데 사용한다고 생각하자
13.6.2 skipLibCheck
소스 코드에 명시적으로 포함되지 않은 선언 파일에서 타입검사를 생략하도록 지시하는 컴파일 옵션.
공유된 라이브러리의 정의가 서로 다르고 충돌할 수 있는 패키지 의존성을 많이 사용하는 애플리케이션에서 유용하다 이는 타입 검사 일부를 건너뛰는 작업으로 성능을 개선키므로 대부분의 프로젝트에서 활성화 시키는것이 좋다.
13.6.3 엄격모드
타입스크립트의 타입 검사 컴파일러 옵션 대부분은 엄격모드로 그룹화 된다.
엄격모드의 기본값은 false다.
noImplicitAny와 stringNullChecks는 타입 안전 코드를 작성하는데 특히 유용하다.
noImplicitAny
암시적으로 타입이 any로 대체될때 타입검사기가 오류를 발생하도록 지시하는 옵션
strictBindCallApply
초기 타입스크립트에는 Function.apply, Function.bind, Function.call 함수 유틸리티를 나타낼 만큼 충분한 타입 시스템이 없어 any타입을 사용했지만 이 옵션을 활성화하면 타입을 지원해준다.
strictFunctionTypes
함수 매개변수의 타입을 좀더 엄격하게 관리해주는 옵션.
매개변수가 옵셔널 매개변수를 갖는 함수인 함수에 단일 타입의 매개변수를 갖는 함수를 인수로 전달하면 기본 타입검사에서는 허용하지만, 이옵션을 활성화하면 오류가 발생한다(매개변수 타입이 옵셔널로 완전히 동일해야 오류가 발생하지 않는다)
strictNullChecks
기본적으로 모든 코드의 타입에 null | undefined 타입이 허용되지만, 이옵션을 활성화하면 특정 타입에 null | undefined타입을 할당하면 오류를 발생한다.(타입스크립트의 모범사례는 이 옵션을 활성화시키는것이다)
strictPropertyInitialization
클래스의 초기화가 없고 생성자에 확실하게 할당되지 않은 클래스 속성에 타입오류를 발생시키는 옵션(타입스크립트의 모범사례는 이 옵션을 활성화시키는것이다)
useUnknownInCatchVariables
타입스크립트의 기본 catch절 error 타입을 unknown으로 변경하는 옵션.(타입스크립트의 모범사례는 이 옵션을 활성화시키는것이다) - 기본타입 검사기에서는 any이며, 이를 억지로 명시적 어셔션등의 방법으로 오류가 특정 타입이 될 수 있는 것으로 가정하는 것이 언제나 안전하지는 않기 때문.
13.7 모듈
13.7.1 module
타입스크립트는 어떤 모듈 시스템으로 변환된 코드를 사용할지 결정하기 위해 module 컴파일러 옵션을 제공한다.
예를들어 ECMA스크립트 모듈로 작성된 소스코드를 아래와 같은 명령어로 CommonJS모듈로 출력하도록지시할 수 있다.
tsc --module commonjs
TSConfig에서도 가능.
{
"compilerOptions" : {
"module": "commonjs",
}
}
target컴파일러 옵션이 “es3”나 “es5”인 경우 module컴파일러 옵션의 기본값은 “commonjs”이고, 그렇지않으면 ECMA스크립트 모듈로 출력하도록 지정하기위해 “es2015”로 기본 설정된다.
13.7.2 moduleResolution
모듈 해석(module resolution)이란 import에서 가져온 경로가 module에 매핑되는 과정을 의미한다.
이때 타입스크립트가 선호하는 로직은 두 가지중 하나이다.
- node: 기존 Node.js와 같은 CommonJS 리졸버 에서 사용하는 동작
- nodenext: ECMA스크립트 모듈에 대해 지정된 동작에 맞게 조정
{
"compilerOptions": {
"moduleResolution": "nodenext"
}
}
두 값은 유사하게 동작하여 차이가 거의 없다.
13.7.3 CommonJS와의 상호 운용성
CommonJS와 ECMA스크립트 모듈 내보내기 및 가져오기형식 비교
타입스크립트에서는 두 방식간을 상호운용할 수 있는 컴파일 옵션을 제공한다.
esModuleInterop
이 옵션은 위 표에서 ECMA스크립트 모듈이 기본 또는 네임스페이스 가져오기에 대한 ECMA스크립트 방식을 따르지 않아도 모듈을 가져올 수 있도록 한다.(호환을 위한 로직을 내부적으로 추가하여가능하게함)
allowSyntheticDefaultImports
CommonJS 네임스페이스 내보내기 파일을 ECMA스크립트의 기본 가져오기로 사용할 수 있게 해주는 옵션.
이 옵션은 다음중 하나가 true인 경우에만 true로 설정된다.
- module옵션이 “system”인 경우.(오래되고 거의 사용하지 않는 모듈 형식이다)
- esModuleInterop이 true이고 module이 “es2015” 또는 “esnext”와 같은 ECMA 스크립트 모듈 형식이 아닌 경우
13.7.4 isolatedModules
프로젝트에서 타입스크립트가 아닌 다른 도구를 사용해 자바스크립트로 변환하는 경우에는 isolationModules를 활성화하는것이 좋다.
13.8 자바스크립트
타입스크립트는 .js, .jsx확장자를 가진 파일을 무시하지만, allowJs와 checkJs 컴파일러 옵션을 사용하면 자바스크립트 파일을 읽고, 컴파일하고, 제한된 기능이지만 타입 검사도 할 수 있다.
- 기존 자바스크립트 프로젝트에 타입스크립트를 적용할때의 일반적인 전략으로, 타입스크립트로 변환된 몇개의 파일에서부터 점점 늘려가며 전환하는방식이 있다.
13.8.1 allowJs
자바스크립트파일에 선언된 구문을 타입스크립트 파일에서 타입 검사를 하도록 허용하는 옵션.
// index.ts
import { value } from "./values";
console.log(`${value.toUpperCase()}`);
// index.js
export const value = "test String";
기본적으로 allowJs를 활성화시키지않으면, .ts파일에서 .js파일을 불러올때 any타입이 되거나 모듈자체를 불러올수 없게되지만, allowJs를 활성화하면 위 코드를 기준으로 value가 string임을 검사한다.
13.8.2 checkJs
자바스크립트 파일도 타입검사가 가능하게 해주는 옵션
- checkJs가 동작하려면 allowJs 옵션이 true로 설정되어 있어야함
- .js와 .jsx파일에서 타입 검사기 활성화하기
@ts-check
파일 상단에 // @ts-check 주석을 사용해 파일별로 checkJs를 활성화 할 수 있다.
13.8.3 JSDoc 지원
자바스크립트에는 타입스크립트만큼의 타입구문이 없기 때문에 자바스크립트 파일에 선언된 값의 타입은 명확하지 않을 수 있다. ex. 인터페이스
allowJs와 checkJs가 활성화되면 타입스크립트는 코드의 모든 JSDoc정의를 실제로 인식한다.
13.9 구성 확장
13.9.1 extends
TSConfig는 extends 옵션을통해 확장할 수 있다.
클래스의 extends키워드와 유사하게 동작하고, 확장할 tsconfig.json파일에대해 tsconfig.base.json 파일을 생성한다.
//tsconfig.base.json
{
"compilerOptions" :{
"strict": true
}
}
//pakages/core/tsconfig.json
{
"extends": "../../tsconfig.base.json",
"includes": ["src"]
}
13.9.2 구성 베이스
처음부터 —init 제안을 하는 대신, 특정 런타임 환경에 맞는 미리 만들어진 베이스TSConfig 파일로 시작할 수 있다.
- @tsconfig/recommended
- @tsconfig/node16
등 @tsconfig/ 아래의 npm 패키지 레지스트리에서 사용할 수 있다.
https://github.com/tsconfig/bases
13.10 프로젝트 레퍼런스
대규모 프로젝트에서는 프로젝트의 서로 다른 영역에 서로 다른 구성 파일을 사용 하는 것이 유용하다.
타입스크립트에서는 여러 개의 프로젝트를 함께 빌드하는 프로젝트 레퍼런스 시스템을 정의할 수 있다.
이점
- 특정 코드 영역에 대해 다른 컴파일러 옵션을 지정할 수 있다.
- 타입스크립트는 개별 프로젝트에 대한 빌드 출력을 캐시할 수 있으므로 종종 대규모 프로젝트의 빌드 시간이 빨라진다.
- 코드의 개별 영역을 구조화하는데 유용한 의존성 트리(특정 프로젝트가 다른 특정 프로젝트에서만 파일을 가져오게 허용)를 실행한다.
→ 프로젝트 레퍼런스는 모노레포, 모듈식 컴포넌트 시스템처럼 별개의 코드 영역 여러개로 구성된 대규모 프로젝트에서 사용한다.
13.10.1 composite
빌드 입력과 비교해 빌드 출력이 최신 상태인지 여부를 확인하고 싶을때 활성화시키는 옵션
13.10.2 references
core/디렉터리를 입력으로 참조하도록 shell/ 디렉터리를 설정한다.
// shell/tsconfig.json
{
"references" : [
{"path": "../core"}
]
}
13.10.3 빌드 모드
프로젝트 레퍼런스를 사용하도록 설정되면 빌드모드에서 -b 또는 —b CLI 플래그를 통해 tsc를 사용할 수 있습니다. 빌드모드는 tsc를 프로젝트 빌드 코디네이터같은 것으로 향상시킨다.
타입스크립트의 빌드 모드는 TSConfig가 제공될때 다음 내용을 수행한다.
- TSConfig의 참조된 프로젝트를 찾는다.
- 최신 상태인지 감지한다.
- 오래된 프로젝트를 올바른 순서로 빌드한다.
- 제공된 TSConfig 또는 TSConfig의 의존성이 변경된 경우 빌드한다.
→ 타입스크립트 빌드 모드 기능은 최신 프로젝트를 다시 빌드하는 것을 건너뛰도록 해 빌드 성능을 크게 향상 시킨다.
코디네이터 구성
저장소에서 타입스크립트 프로젝트 레퍼런스를 설정하는 편리한 방법은 빈 파일 배열과 저장소의 모든 프로젝트 레퍼런스에 대한 레퍼런스를 사용해 최상위 레벨의 tsconfig.json을 설정하는 것이다.
최상위 TSConfig는 타입스크립트가 파일 자체를 빌드하도록 지시하지 않는다.
대신 필요에따라 참조된 프로젝트를 빌드하도록 타입스크립트에 알리려는 역할만한다.
다음 tsconfig.json은 저장소의 packages/core와 packages/sheel 프로젝트를 빌드하는 것을 나타낸다.
//tsconfig.json
{
"files": [],
"references": [
{"path": "./packages/core"},
{"path": "./packages/shell"}
]
}