TypeScript - Learning TypeScript Chap. 13 Configuration Options

이소라·2023년 6월 15일
0

TypeScript

목록 보기
26/28

13.1 tsc Options

  • TypeScript 파일을 컴파일하기 위해 tsc 명령을 실행합니다.
    • 예 : index.ts 파일을 컴파일 하기 위해 tsc index.ts를 실행합니다.
tsc index.ts
  • tsc 명령은 TypeScript의 대부분의 옵션을 -- 플래그로 사용할 수 있습니다.
    • 예 : index.ts 파일에서 tsc를 실행할 때 index.js 파일 생성을 건너뛰려면 --noEmit 플래그를 전달합니다.
tsc index.ts --noEmit
  • tsc --help를 실행해 일반적으로 사용하는 CLI 플래그 목록을 가져올 수 있습니다.

13.1.1 Pretty Mode

  • tsc CLI는 색상과 간격의 스타일을 지정해 가독성을 높이는 pretty 모드를 지원합니다.

    • 출력 터미널이 여러 색상 텍스트를 지원한다는 것을 감지하면 기복적으로 pretty 모드로 설정됩니다.
  • 여러 가지 색이 없는 더 압축된 CLI 출력을 선호한다면 tsc 명령에 명시적으로 --pretty false 플래그를 제공해 TypeScript에 더 간결하고 색상이 없는 형식을 사용하도록 지시합니다.


13.1.2 Watch Mode

  • tsc CLI에 -w--watch 플래그를 제공해 watch 모드를 사용할 수 있습니다.
    • watch 모드를 사용하면 종료하는 대신 TypeScript를 무기한 실행 상태로 유지하고 모든 오류의 실시간 목록을 가져와서 터미널을 지속적으로 업데이트합니다.

    • watch 모드는 여러 파일에 걸쳐서 리팩터링 같은 대규모 변경 작업을 할 때 특시 유용합니다.

      • TypeScript의 타입 오류를 일종의 체크리스트로 사용해 아직 정리해야 할 항목으로 사용할 수 있습니다.



13.2 TSConfig Files

  • 대부분의 구성 옵션을 디렉터리의 tsconfig.json(TSConfig) 파일에 구체적으로 명시할 수 있습니다.
    • tsconfig.json의 존재는 해당 디렉터리가 TypeScript 프로젝트의 루트임을 나타냅니다.
  • tsc를 실행하면 해당 tsconfig.json 파일의 모든 구성 옵션을 읽습니다.
    • tsc 명령에 tsconfig.json 파일이 있는 디렉터리 경로를 -p 또는 --project 플래그로 전달합니다.
tsc -p path/to/tsconfig.json
  • VS Code 같은 IDE는 IntelliSense 기능을 제공할 때 TSConfig의 구성을 따릅니다.

13.2.1 tsc --init

  • tsc 명령에 --init 플래그를 전달하여 tsconfig.json 파일을 생성할 수 있습니다.
tsc --init
  • 새로 생성된 TSConfig 파일에서 설정된 기본값은 대부분의 프로젝트에 적용 가능합니다.

13.2.2 CLI vs. Configuration

  • CLI와 TSConfig 파일에서 사용 가능한 대부분의 옵션은 다음 2 가지 범주 중 하나로 분류됩니다.

    • 컴파일러
      • 포함된 각 파일이 TypeScript에 따라 컴파일되거나 타입을 확인하는 방법
    • 파일
      • TypeScript가 실행될 파일과 실행되지 않을 파일
  • 2 가지 범주 외에 프로젝트 레퍼런스(project reference)와 같은 다른 설정은 TSConfig 파일에서만 사용할 수 있습니다.

Tip

  • CLI 또는 production 빌드를 위한 일회성 변경과 같은 설정이 tsc CLI에 제공되는 경우, TSConfig 파일에 명시된 모든 값을 재정의합니다.



13.3 File Inclusions

  • 기본적으로 tsc는 현재 디렉터리와 하위 디렉터리에 숨겨지지 않는 모든 .ts 파일에서 실행되고, 숨겨진 디렉터리와 node_modules 디렉터리는 무시합니다.
  • TypeScript 구성은 실행할 파일 목록을 수정할 수 있습니다.

13.3.1 include

  • 파일을 포함하는 가장 흔한 방법으로 TSConfig 파일의 최상위 include 속성을 사용합니다.
  • include 속성에 TypeScript 컴파일에 포함될 디렉터리와 파일을 설명하는 문자열 배열을 명시합니다.
{
  "include": ["src"]
}
  • 위의 구성 파일은 tsconfig.json과 관련된 src/ 디렉터리 안에 모든 TypeScript 소스 파일을 재귀적으로 포함합니다.

  • 포함된 파일을 더 세밀하게 제어하기 위해 include 문자열에 글로브 와일드 카드가 허용합니다.

    • * : 0개 이상의 문자와 일치
    • ? : 하나의 문자와 일치
    • **/ : 모든 레벨에 중첩된 모든 디렉터리와 일치
{
  "include": [
    "typings/**/*.d.ts",
    "src/**/*??.*"
  ]
}
  • 위의 구성 파일은 typings/ 하위의 중첩된 디렉터리의 .d.ts 파일과 확장자 앞의 파일 명에 적어도 2개 이상의 문자를 가진 src/ 하위의 파일만을 포함합니다.

  • 대부분의 프로젝트에서는 ["src"]와 같은 간단한 include 컴파일러 옵션으로도 충분합니다.


13.3.2 exclude

  • 프로젝트의 include 파일 목록에 TypeScript로 컴파일할 수 없는 파일이 포함된 경우가 있습니다.
    • TSConfig 파일의 최상위 exclude 속성에 해당 파일의 경로를 지정하여 include에서 그 경로를 생략합니다.
    • exclude 속성에 TypeScript 컴파일에서 제외할 디렉터리와 파일을 설명하는 문자열 배열이 허용됩니다.
{
  "exclude": ["**/external", "node_modules"],
  "include": ["src"]
}
  • 위의 구성 파일은 중첩된 external 디렉터리와 node_modules 디렉터리 내의 모든 파일을 제외하고 src/ 내의 모든 파일을 포함합니다.

  • 프로젝트 내 폴더에 노드 모듈을 설치하는 대부분의 JavaScript 프로젝트는 exclude에 "node_modules"를 포함합니다.

  • excludeinclude의 시작 목록에서 파일을 제거하는 작업만 수행합니다.

    • TypeScript는 비록 가져온 파일이 exclude 목록에 명시적으로 나열되어 있더라도 포함된 파일에 따라 가져온 모든 파일에서 실행됩니다.



13.4 Alternative Extensions

  • TypeScript는 기본적으로 확장자가 .ts인 모든 파일을 읽을 수 있습니다.
  • 그러나 일부 프로젝트는 JSON 모듈 또는 React와 같은 UI 라이브러리를 위한 JSX 구문처럼 확장자가 다른 파일을 읽을 수 있어야 합니다.

13.4.1 JSX Syntax

  • JSX는 JavaScript로 컴파일되는 JavaScript 구문의 확장입니다.
const MyComponent = () => {
  // return React.createElement("div", null, "Hello, world")와 같음
  return <div>Hello, world!</div>
};
  • 파일에서 JSX 구문을 사용하기 위해 다음 2 가지를 수행해야 합니다.
    1. 구성 옵션에서 "jsx" 컴파일러 옵션을 활성화합니다.
    2. ".tsx" 확장자로 파일의 이름을 지정합니다.

jsx

  • TypeScript가 .tsx 파일에 대한 JavaScript 코드를 내보내는 방법은 "jsx" 컴파일러 옵션에서 사용되는 값으로 결정됩니다.
입력 코드출력 코드출력 파일 확장자
"preserve"<div /><div />.jsx
"react"<div />React.createElement("div").js
"react-native"<div /><div />.js
  • jsx에 대한 값은 tsc CLI 또는 TSConfig 파일에 제공합니다.
tsc --jsx preserve
{
  "compileOptions": {
    "jsx": "preserve"
  }
}
  • TypeScript의 내장된 트랜드파일러를 직접적으로 사용하지 않고 Babel과 같은 별도의 도구를 사용하는 경우, "jsx"에 대해 허용된 값을 사용할 수 있습니다.
  • Next.js 또는 Remix와 같은 최신 프레임워크고 구축된 대부분의 웹 앱은 React 구성 및 컴파일 구문을 처리합니다.
    • 이러한 프레임워크 중 하나를 사용하면 TypeScript의 내장 트랜스파일러를 직접 구성할 필요가 없습니다.

. tsx 파일의 제네릭 화살표 함수

  • 제네릭 화살표 함수의 구문이 JSX 구문과 충돌합니다.
    • .tsx 파일에서 화살표 함수에 대한 타입 인수 <T>를 작성하려고 하면, T 요소의 시작 태그로 인식하여 T 태그의 종료 태그가 없기 때문에 구문 오류가 발행합니다.
const identity = <T>(input: T) => input;
// Error: JSX element 'T' has no corresponding closing tag.
  • 이런 구문 모호성을 해결하기 위해 타입 인수에 =unknown 제약 조건을 추가할 수 있습니다.
    • 타입 인수 기본값이 unknown이므로 코드 동작이 전혀 변경되지 않습니다.
    • 단지 JSX 요소가 아닌 타입 인수를 읽도록 TypeScript에 지시합니다.
const identity = <T = unknown>(input: T) => input; // Ok

13.4.2 resolveJsonModule

  • TypeScript는 resolveJsonModule 컴파일러 옵션을 true로 설정하면 .json 파일을 읽을 수 있습니다.

    • 이렇게 하면 .json 파일을 마치 객체를 내보내는 .ts 파일인 것처럼 가져오고 해당 객체의 타입을 const 변수인 것처럼 유추합니다.
  • 객체가 포함된 JSON 파일이라면 구조 분해 가져오기(destructuring import)를 사용합니다.

// activist.json
{
  "activist": "Mary Astell"
}
// useActivist.ts
import { activist } from './activist.json';

console.log(activist); // "Mary Astell"
  • esModuleInterop 컴파일러 옵션이 활성화된 경우에는 기본 가져오기(default import)를 사용할 수 있습니다.
// useActivist.ts
import activist from './activist.json';

console.log(activist); // "Mary Astell"
  • array 또는 number 같은 다른 리터럴 타입을 포함한 JSON 파일이라면 import 구문으로 *를 사용합니다.
// activists.json
[
  "Ida B. Wells",
  "Sojourner Truth",
  "Tawakkul Karman"
]
// useActivists.ts
import * as activists from "./activists.json";

console.log(`${activists.length} activists`); // "3 activists"



13.5 Emit

  • Babel 같은 전용 컴파일러 도구의 등장으로 일부 프로젝트에서는 TypeScript의 역할이 타입 검사만으로 축소되었지만, TypeScript 구문을 JavaScript로 컴파일하기 위해 여전히 TypeScript에 의존하고 있는 프로젝트들이 많습니다.

13.5.1 outDir

  • 기본적으로 TypeScript는 출력 파일을 소스 파일과 동일한 위치에 생성합니다.
fruits/
	apple.js
    apple.ts
vegetables/
	zucchini.js
    zucchini.ts
  • TypeScript의 outDir 컴파일러 옵션을 사용하면 출력 파일의 루트 디렉토리를 다르게 지정할 수 있습니다.
tsc --outDir dist
  • 위 명령어를 실행하면 dist/ 폴더 내에 출력 파일을 생성합니다.
dist/
	fruits/
    	apple.js
    vegetables/
    	zucchini.js
fruits/
	apple.ts
vegetables/
    zucchini.ts
  • TypeScript는 모든 입력 파일에서 가장 긴 공통 하위 경로를 찾아 출력 파일을 저장할 루트 디렉터리를 계산합니다.
    • 즉, 모든 입력 소스 파일을 단일 디렉터리에 배치하는 프로젝트는 해당 디렉터디를 루트로 처리합니다.
tsc --outDir lib
  • 모든 입력 파일을 src/ 디렉터리에 넣고 위 명령어를 실행하면 lib/ 폴더 내에 출력 파일을 생성합니다.
lib/
	fruits/
    	apple.js
    vegetables/
    	zucchini.js
src/
	fruits/
		apple.ts
    vegetables/
    	zucchini.ts
  • rootDir 컴파일러 옵션은 해당 루트 디렉터리를 명시적으로 지정하기 위해 존재하지만, "." 또는 "src" 이외의 값을 사용할 일은 거의 없습니다.

13.5.2 target

  • TypeScript는 ES3(1993년경)과 같은 오래된 환경에서 실행할 수 있는 JavaScript 출력 파일을 생성할 수 있습니다.

    • 또한 대부분의 환경은 JavaScript의 최신 구문 기능을 지원합니다.
  • TypeScript는 JavaScript 코드 구문을 지원하기 위해 어느 버전까지 변환해야 하는지를 지정하는 target 컴파일러 옵션을 제공합니다.

    • target을 지정하지 않으면 이전 버전과의 호환성을 위해 기본적으로 "es3"이 지정됩니다.
    • tsc --init은 기본적으로 "es2016"을 지정하도록 설정되어 잇습니다.
    • 대상 플랫폼에 따라 가능한 한 최신 JavaScript 구문을 사용하는 것이 좋습니다.
      • 오래된 환경에서 최신 JavaScript 기능을 지원하려면 더 많은 JavaScript 코드를 생성해야 하므로, 파일 크기가 조금 더 커지고 런타임 성능이 조금 저하됩니다.

Tip

  • 2022년에는 전 세계 사용자의 0.1% 이상을 서비스하는 브라우저의 모든 배포 버전은 최소한 모든 ECMAScript2019와 거의 모든 ECMAScript2020~2021을 지원합니다.
  • 또한 LTS 지원 버전의 Node.js는 모든 ECMAScript2021을 지원합니다.
    • 그러므로 target을 적어도 "es2019" 이상으로 지정하지 않을 이유가 없습니다.
// ES2015의 const, ES2020의 nullish 병합 연산자 ??
function defaultNameAndLog(nameMaybe: string | undefined) {
  const name = nameMaybe ?? 'anonymous';
  console.log('From', nameMaybe, 'to', name);
  return name;
}
tsc --target es2020
  • target을 ""es2020"" 이상으로 지정하면, const와 ??는 지원되는 구문 기능이므로 TypeScript는 코드에서 :string | undefined만 제거합니다.
function defaultNameAndLog(nameMaybe) {
  const name = nameMaybe ?? 'anonymous';
  console.log('From', nameMaybe, 'to', name);
  return name;
}
tsc --target es2015
  • target을 ""es2015""부터 ""es2019""까지 중 하나로 지정하면, ?? 구문은 지원되지 않으므로 이전 버전의 JavaScript에서 상응되는 코드로 컴파일됩니다.
function defaultNameAndLog(nameMaybe) {
  const name = nameMaybe !== null && nameMaybe !== void 0 
  	? nameMaybe
  	: 'anonymous';
  console.log('From', nameMaybe, 'to', name);
  return name;
}
tsc --target es3
  • target을 ""es3""이나 ""es5""로 지정하면, const 구문도 지원하지 않으므로 상응하는 var로 변환해야 합니다.
function defaultNameAndLog(nameMaybe) {
  var name = nameMaybe !== null && nameMaybe !== void 0 
  	? nameMaybe
  	: 'anonymous';
  console.log('From', nameMaybe, 'to', name);
  return name;
}

13.5.3 Emitting Declarations

  • 대부분의 패키지는 TypeScript의 declaration 컴파일러 옵션을 사용해 소스 파일에서 .d.ts 출력 파일을 내보냅니다.
tsc --declaration
// tsconfig.json
{
  "compilerOptions": {
    "declaration": true,
  }
}
  • .d.ts 출력 파일은 소스 파일과 동일한 위치에 내보내집니다.
fruits/
	apple.d.ts
	apple.js
    apple.ts
vegetables/
	zucchini.d.ts
	zucchini.js
    zucchini.ts

emitDeclarationOnly

  • emitDeclarationOnly은 TypeScript가 .js와 .jsx 파일 없이 선언 파일만 내보내도록 지시하는 declaration 컴파일러의 추가 옵션입니다.
    • 이는 외부 도구를 사용해 출력 JavaScript를 생성하지만 여전히 TypeScript를 사용해 .d.ts 파일을 생성하려는 프로젝트에 유용합니다.
tsc --emitDeclarationOnly
// tsconfig.json
{
  "compilerOptions": {
    "emitDeclarationOnly": true,
  }
}
fruits/
	apple.d.ts
    apple.ts
vegetables/
	zucchini.d.ts
    zucchini.ts
  • emitDeclarationOnly가 활성화된 경우, declaration 또는 composite 컴파일러 옵션을 활성화해야 합니다.

13.5.4 Source Maps

  • 소스 맵(source map) 출력 파일의 내용이 원본 소스 파일과 어떻게 일치하는지에 대한 설명입니다.

    • 소스 맵은 출력 파일을 탐색할 때 디버거 같은 개발자 도구에서 원본 소스 코드를 표시하도록 설정합니다.
    • 브라우저 개발자 도구와 IDE에서 디버깅하는 동안 원본 소스 파일 내용을 볼 수 있도록하는 기각적인 디버거에 특히 소스 맵이 유용합니다.
  • TypeScript 는 출력 파일과 함께 소스 맵을 출력하는 기능도 제공합니다.

sourceMap

  • TypeScript의 sourceMap 컴파일러 옵션을 사용하면 .js 또는 .jsx 출력 파일과 함께 .js.map 또는 .jsx.map 소스 맵을 출력할 수 있습니다.
tsc --sourceMap
fruits/
	apple.js
    apple.js.map
    apple.ts
vegetables/
	zucchini.js
    zucchini.js.map
    zucchini.ts

declarationMap

  • TypeScript는 .d.ts 선언 파일에 대한 소스 맵도 생성할 수 있습니다.
  • declarationMap 컴파일러 옵션은 원본 소스 파일에 해당하는 각 .d.ts에 대한 .d.ts.map 소스 맵을 생성하도록 지시합니다.
    • declarationMap을 활성화하면 VS Code와 같은 IDE에서 [Go to Definition] 기능으로 원본 소스 파일로 이동할 수 있습니다.
tsc --declarationMap
fruits/
	apple.d.ts
    apple.d.ts.map
	apple.js
    apple.ts
vegetables/
	zucchini.d.ts
    zucchini.d.ts.map
	zucchini.js
    zucchini.ts

13.5.5 noEmit

  • 다른 도구를 이용해 소스 파일을 컴파일하고, JavaScript를 출력하는 프로젝트에서 TypeScript는 파일 생성을 모두 건너뛰도록 지시할 수 있습니다.
  • noEmit 컴파일러 옵션을 활성화하면 TypeScript가 파일 생성을 모두 건너뛰고 온전히 타입 검사기로만 작동합니다.
tsc --noEmit
  • 위 명령어를 실행하면, 어떠한 파일도 생성되지 않습니다.
    • TypeScript는 발견한 구문 또는 타입 오류만을 보고합니다.



13.6 Type Checking

  • 대부분의 TypeScript 구성 옵션은 타입 검사기를 제어합니다.
    • 구성 옵션을 느슨하게 구성해 오류가 완전히 확실할 때만 타입 검사 오류를 보고하도록 하거나, 구성 옵션을 엄격하게 구성해 거의 모든 코드를 올바르게 잘 입력하도록 요구할 수 있습니다.

13.6.1 lib

  • 먼저 TypeScript가 런타임 환경에 있다고 가정하는 전역 API는 lib 컴파일러 옵션으로 구성할 수 있습니다.
    • lib 컴파일러 옵션은 브라우저 타입 포함을 나타내는 domtarget 컴파일러 옵션을 기본값으로 하는 문자열 배열을 사용합니다.
    • lib 설정을 변경하는 유일한 이유는 브라우저에서 실행되지 않는 프로젝트에서 기본으로 포함된 dom을 제거하기 위함입니다.
tsc --lib es2020
// tsconfig.json
{
  "complierOptions": {
    "lib": ["es2020"]
  }
}
  • 또는 최신 JavaScript API를 지원하기 위해 폴리필(polyfill)을 사용하는 프로젝트에서 lib 컴파일러 옵션을 사용해 domECMAScript의 특정 버전을 포함할 수 있습니다.
tsc --lib dom,es2021
// tsconfig.json
{
  "complierOptions": {
    "lib": ["dom", "es2021"]
  }
}
  • 올바른 런타임 폴리필을 모두 제공하지 않은 상태에서는 lib을 수정하지 않도록 주의하세요.
    • ES2020까지만 지원하는 플랫폼에서 실행되는 lib"es2021"로 설정된 프로젝트에서 String.replaceAll과 같은 ES2021이상에 정의된 API를 사용하려고 하면 런타임 오류가 발생할 수 있습니다.
const value = "a b c";
// Uncaught TypeError: value.replaceAll is not a function
value.replaceAll(" ", ", ");

Tip

  • lib 컴파일러 옵션은 내장된 언어 API를 나타내는 데 사용하고, target 컴파일러 옵션은 존재하는 구문 기능을 나타내는 데 사용한다고 생각하세요.

13.6.2 skipLibCheck

  • TypeScript는 소스 코드에 명시적으로 포함되지 않은 선언 파일에서 타입 검사를 건너뛰도록 하는 skipLibCheck 컴파일러 옵션을 제공합니다.
    • skipLibCheck 옵션은 공유된 라이브러리의 정의가 서로 다르고 충돌할 수 있는 패키지 의존성을 많이 사용하는 애플리케이션에 유용합니다.
tsc --skipLibCheck
{
  "complierOptions": {
    "skipLibCheck": true
  }
}
  • skipLibCheck는 타입 검사 일부를 건너뛰는 작업으로 TypeScript의 성능을 개선합니다.
    • 따라서 대부분의 프로젝트에서 skipLibCheck 옵션을 활성화하는 것이 좋습니다.

13.6.3 Strict Mode

  • TypeScript의 타입 검사 컴파일러 옵션 대부분은 TypeScript의 Strict Mode로 그룹화됩니다.
    • strict 컴파일러 옵션이 활성화되면 타입 검사기에 일부 추가적인 검사를 켜도록 지시합니다.
    • strict 옵션 중에 noImplicitAnystrictNullChecks는 타입 안전 코드를 적용하는 데 특히 유용하고 영향력이 있습니다.
tsc --strict
// tsconfig.json
{
  "complierOptions": {
    "strict": true
  }
}
  • 특정 검사를 제외한 모든 Strict Mode 검사를 활성화하고 싶다면 strict를 활성화하고 특정 검사를 명시적으로 비활성화할 수 있습니다.
    • 다음 명렬어는 noImplicitAny를 제외한 모든 엄격 모드를 활성화합니다.
tsc --strict --noImplicitAny false
// tsconfig.json
{
  "complierOptions": {
    "noImplicitAny": false,
    "strict": true
  }
}

noImplicitAny

  • TypeScript는 매개변수 또는 속성의 타입을 유추할 수 없는 경우라면 any 타입으로 가정합니다.
    • any 타입은 TypeScript의 타입 검사를 대부분 우회할 수 있으므로 이러한 암시적 타입을 허용하지 않는 것이 좋습니다.
  • noImplicitAny 컴파일러 옵션은 암시적 any로 대체될 때 TypeScript에 타입 검사 오류가 발생하도록 지시합니다.
// Error: Parameter 'message' implicitly has an 'any' value
const logMessage = (message) => {
  console.log(`Message: ${message}!`);
}
  • noImplicitAny 오류는 오류가 발생한 위치에 type annotation을 추가하면 대부분 해결됩니다.
// Ok
const logMessage = (message: string) => {
  console.log(`Message: ${message}!`);
}
  • 또는 함수 매개변수의 경우, 함수의 타입을 선언하여 noImplicitAny 오류를 해결할 수 있습니다.
type LogsMessage = (message: string) => void;

const logMessage : LogsMessage = (message) => {
  console.log(`Message: ${message}!`);
}

strictBindCallApply

  • TypeScript가 처음 출시되었을 때 내장된 Function.apply, Function.bind, Function.call 함수 유틸리티를 나타낼 수 있을 만큼 충분한 타입 시스템 기능이 없었습니다.
    • 기본적으로 이런 함수는 함수 인수 목록에 대해 any를 사용해야 했고 타입 안정성과는 매우 거리가 멀었습니다.
function getLength(text: string, trim?: boolean) {
  return trim ? text.trim().length : text.length;
}

// 함수 타입 : (thisArg: Function, argArray?: any) => any
getLength.apply;
// 반환 타입 : any
getLength.bind(undefined, "abc123");
// 반환 타입 : any
getLength.call(undefined, "abc123", true);
  • 이제 TypeScript의 타입 시스템 기능은 이러한 함수의 제네릭 나머지 인수를 나타내기에 충분히 강력하고 함수에 더 제한적인 타입 사용을 허용합니다.

  • strictBindCallApply를 활성화하면 getLength 함수 변형에 대해 훨씬 더 정확한 타입을 사용할 수 있습니다.

function getLength(text: string, trim?: boolean) {
  return trim ? text.trim().length : text.length;
}

// 함수 타입 : (thisArg: typeof getLength, args: [text: string, trim?: boolean]) => number
getLength.apply;
// 반환 타입 : (trim?: boolean | undefined) => number
getLength.bind(undefined, "abc123");
// 반환 타입 : number
getLength.call(undefined, "abc123", true);
  • TypeScript의 모범 사례는 strictBindCallApply를 활성화하는 것입니다.
    • 내장된 함수 유틸리티에 대한 개선된 타입 검사는 이를 활용하는 프로젝트의 타입 안전성을 개선하는 데 도움이 됩니다.

strictFunctionTypes

  • strictFunctionTypes 컴파일러 옵션은 함수 매개변수 타입을 약간 더 엄격하게 검사합니다.

    • 함수의 매개변수가 다른 함수 타입의 매개변수 하위 타입인 경우, 함수 타입은 더 이상 다른 함수 타입에 할당 가능한 것으로 간주되지 않습니다.
  • 다음 코드는 checkOnNumber 함수는 number | string를 매개변수로 받는 함수를 인수로 받아야 하지만, string만 매개변수로 받는 stringContainsA 함수를 인수로 받습니다.

function checkOnNumber(containsA: (input: number | string) => boolean) {
  return containsA(1337);
}

function stringCountainsA(input: string) {
  return !!input.match(/a/i);
}

checkOnNumber(stringContainsA);
  • TypeScript의 기본 검사는 checkOnNumber(stringContainsA)를 허용하고, 런타임에서 stringContainsA의 매개변수가 number인 경우 .match()를 호출하려고 하면 오류가 발생합니다.

  • strictFunctionTypes가 적용된 상태에서 checkOnNumber(stringContainsA)는 타입 검사 오류를 발생시킵니다.

checkOnNumber(stringContainsA);
// Error: Argument of type '(input: string) => boolean' is not assignable
// to paramter of type '(input: string | number) => boolean'.
//	Types of parameters 'input' and 'input' are incompatible.
//		Type 'string | number' is not assignable to type 'string'.
//			Type 'number' is not assignable to type 'string'.

Note

  • 기술적인 측면에서 함수 매개변수는 bivariant에서 contravariant로 전환됩니다.
    • bivariant는 상위 타입과 하위 타입을 허용합니다.
    • contravariant는 상위 타입을 허용하지만, 하위 타입은 허용하지 않습니다.

strictNullChecks

  • TypeScript의 strictNullChecks 플래그를 비활성화하면 코드의 모든 타입에 null | undefined가 추가되고, 모든 변수가 null 또는 undefined를 받을 수 있도록 허용합니다.

  • 다음 코드에서 strictNullChecks를 활성화한 경우, string 타입인 value에 null을 할당하면 타입 오류가 발생합니다.

let value: string;
// Ok
value = 'abc123';
// Error: Type 'null' is not assignable to type 'string'
value = null;
  • TypeScript의 모범 사례는 strictNullChecks를 활성화하는 것입니다.
    • 이렇게 하면 충돌을 방지하고 십억 달러의 실수를 제거하는 데 매우 유용합니다.

strictPropertyInitialization

  • TypeScript의 strictPropertyInitialization 플래그는 초기화가 없고, 생성자에 확실하게 할당되지 않은 클래스 속성에서 타입 오류를 발생시킵니다.

  • TypeScript의 모범 사례는 strictPropertyInitialization를 활성화하는 것입니다.

    • 이렇게 하면 클래스 초기화 로직 실수로 인한 충돌을 방지할 수 있습니다.

useUnknownInCatchVariables

  • 모든 언어에서 오류 처리는 본질적으로 안전하지 않은 개념입니다.
    • 이론적으로 모든 함수는 사용자가 작성한 throw 문이나 undefined에서 속성을 읽는 것과 같은 극단적인 경우에 여러 오류를 발생시킵니다.
    • 사실 발생한 오류가 Error 클래스의 인스턴스라는 보장은 없습니다. 코드는 항상 '다른 무언가'를 throw할 수 있습니다.
  • 오류는 그 어떤 것도 될 수 있기 때문에 TypeScript는 오류의 기본 동작으로 any 타입을 제공합니다.
    • 기본적으로 타입이 안전하지 않은 any에 의존하는 비용으로 오류 처리에 대한 유연성을 허용합니다.

다음 코드의 error는 TypeScript가 someExternalFunction()에서 발생 가능한 모든 오류를 알 수 있는 방법이 없기 때문에 타입이 any가 됩니다.

try {
  someExternalFunction();
} catch (error) {
  error; // 기본 타입 : any
}
  • 대부분 any 사용과 마찬가지로 오류를 억지로 명시적 type assertion 또는 narrowing하는 비용보다 unknown으로 처리하는 것이 기술적으로 타당합니다.
    • catch 절의 오류는 any 또는 unknown 타입으로 annotation을 추가할 수 있습니다.
try {
  someExternalFunction();
} catch (error: unknown) {
  error; // 기본 타입 : unknown
}
  • useUnknownInCatchVariables 플래그를 활성화하면, TypeScript의 기본 catch 절의 error 타입은 unknown으로 설정됩니다.

  • TypeScript의 모범 사례는 useUnknownInCatchVariables를 활성화하는 것입니다.

    • 왜냐하면 오류가 특정 타입이 될 수 있다는 것으로 가정하는 것은 언제나 안전하지 않기 때문입니다.



13.7 Modules

  • AMD, CommonJS, ECMAScripts 등 모듈 내용을 내보내고 가져오기 위한 JavaScript의 다양한 시스템은 최신 프로그래밍 언어에서 가장 복잡한 모듈 시스템입니다.

    • JavaScript는 파일이 서로의 컨텐츠를 가져오는 방식이 webpack과 같은 사용자 작성 프레임워크에 따라 구동되는 경우가 많다는 점이 상대적으로 특이합니다.
  • TypeScript는 가장 합리적인 사용자 영역의 모듈 구성을 나타내는 구성 옵션을 제공하기 위해 최선을 다합니다.

    • 새로운 TypeScript 프로젝트 대부분은 표준화된 ECMAScript 모듈 구문으로 작성됩니다.
import { value } from "my-example-lib";

export const logValue = () => console.log(value);

13.7.1 module

  • TypeScript는 어떤 모듈 시스템으로 변환된 코드를 사용할지 결정하기 위해 module 컴파일러 옵션을 제공합니다.

    • ECMAScript 모듈로 소스 코드를 작성할 때 TypeScript는 module 값에 따라 export와 import 문을 다른 모듈 시스템으로 변환할 수 있습니다.
  • 예를 들어 다음 명령어를 실행하면, ECMAScript로 작성된 프로젝트를 CommonJS 모듈로 출력되도록 지시합니다.

tsc --module commonjs
  • 또는 TSConfig에 다음과 같이 module 컴파일러 옵션을 추가해서 CommonJS 모듈로 출력하도록 지시합니다.
// tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs"
  }
}
  • 이전 예제 코드가 다음과 같이 출력됩니다.
const my_example_lib = require("my-example-lib");
exports.logValue = () => console.log(my_example_lib.value);
  • target 컴파일러 옵션이 "es3" 또는 "es5"인 경우 module 컴파일러 옵션의 기본값은 "commonjs"가 됩니다.
    • 그렇지 않으면 ECMAScript 모듈로 출력하도록 지정하기 위해 module 컴파일러 옵션은 "es2015"로 기본 설정됩니다.

13.7.2 moduleResolution

  • 모듈 해석(module resolution)은 import에서 가져온 경로가 moule에 매핑되는 과정입니다.

  • TypeScript는 해당 과정에 로직을 지정하는 데 사용할 수 있는 moduleResolution 옵션을 제공합니다.

  • 일반적으로 다음 전략 중 하나를 제공하는 것을 선호합니다.

    • node : 기존 Node.js와 같은 CommonJS resolver에서 사용하는 동작
    • nodenext : ECMAScript 모듈에 대해 지정된 동작에 맞게 조정
    • bundler : 최신 번들러에서 지정된 동작(a fusion of the ECMAScript module and CommonJS lookup rules in Node.js)에 맞게 조정
      • ECMAScript의 모듈 import, export를 사용하면서 CommonJS의 빠른 파일 찾기 및 확장자 생략 기능 사용함
  • 다음 명령을 실행하면, moduleResolution 컴파일러 옵션이 nodenext로 지정됩니다.

tsc --moduleResolution nodenext
// tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "nodenext"
  }
}

13.7.3 Interoperability with CommonJS

  • JavaScript 모듈로 작업할 때 모듈의 기본 내보내기(default export)와 네임스페이스(namespace) 출력 간에는 차이점이 있습니다.
    • 모듈의 기본 내보내기(default export)는 내보낸 객체의 .default 속성입니다.
    • 모듈의 네임스페이스(namespace)는 내보낸 객체 자체입니다.
  • CommonJSECMAScript 모듈 내보내기 및 가져오기 형식
구문 영역CommonJSECMAScript module
기본 내보내기module.exports.default = value;export default value;
기본 가져오기const { default: value } = require("...")import value from "..."
네임스페이스 내보내기module.exports = value;지원 안 함
네임스페이스 가져오기const value = require("...");import * as value from "..."
  • TypeScript의 타입 시스템은 ECMAScript 모듈 측면에서 파일 가져오기와 내보내기에 대한 합의를 만듭니다.

    • 그러나 프로젝트가 npm 패키지를 의존하는 경우 의존성 일부는 여전히 CommonJS 모듈로 배포됩니다.
    • ECMAScript 모듈 규칙을 준수하는 일부 패키지는 비록 기본 내보내기를 포함하지 않지만, 많은 개발자는 네임스페이스 가져오기보다 간결한 기본 가져오기를 선호합니다.
  • TypeScript는 모듈 형식 간의 상호 운용성(interoperability)을 개선하는 몇 가지 컴파일러 옵션을 제공합니다.

esModuleInterop

  • esModuleInterop 구성 옵션은 module"es2015" 또는 "esnext"와 같은 ECMAScript 모듈 형식이 아닌 경우, TypeScript에서 내보낸 JavaScript 코드에 소량의 로직을 추가합니다.

    • 해당 로직은 ECMAScript 모듈이 기본 또는 네임스페이스 가져오기에 대한 ECMAScript 모듈의 규칙을 준수하지 않은 경우에도 모듈에서 가져올 수 있도록 합니다.
  • esModuleInterop을 활성화하는 이유 중 하나는 기본 내보내기를 제공하지 않는 "react"같은 패키지를 위해서 입니다.

    • 모듈이 "react"" 패키지에서 기본 가져오기를 사용하려고 하면 TypeScript는 esModuleInterop이 호라성화되지 않은 것에 대한 타입 오류를 보고합니다.
import React from "react";
// Error: Module '"file:///node_modules/@types/react/index"' can
// only be default-imported using the 'esModuleInterop' flag.
  • esModuleInterop은 내보낸 JavaScript 코드가 가져오기로 작동하는 방식에 대해서만 직접 변경합니다.

allowSyntheticDefaultImports

  • allowSyntheticDefaultImports 컴파일러 옵션은 타입 시스템에 가져오기 상호 운용성을 알리는 옵션입니다.

    • allowSyntheticDefaultImports 옵션은 ECMAScript 모듈이 호환되지 않는 CommonJS 네임스페이스 내보내기 파일에서 기본 가져오기를 할 수 있음을 타입 시스템에 알립니다.
  • allowSyntheticDefaultImports 옵션은 다음 중 하나가 true인 경우 true로 기본적으로 설정됩니다.

    • module" system"인 경우
    • esModuleInterop이 true이고 module"es2015" 또는 "esnext"와 같은 ECMAScript가 아닌 경우
    • moduleResolutionbundler인 경우
  • esModuleInterop이 true이지만 module"esnext"인 경우, TypeScript는 컴파일된 출력 JavaScript 코드가 가져오기 상호 운용성 지원을 사용하지 않는다고 가정합니다.

import React from "react"
// Error: Module '"file:///node_modules/@types/react/index"' can
// only be default-imported using the 'allowSyntheticDefaultImports' flag.

13.7.4 isolatedModules

  • 한 번에 하나의 파일에서만 작동하는 babel과 같은 외부 트랜스파일러는 타입 시스템 정보를 사용해 JavaScript를 내보낼 수 없습니다.
    • 따라서 타입 정보에 의존하며 JavaScript를 내보내는 TypeScript 구문 기능은 babel과 같은 트랜스파일러에서는 지원되지 않습니다.
    • 프로젝트에서 TypeScript가 아닌 다른 도구를 사용해 JavaScript로 변환하는 경우에는 isolatedModules를 활성화하는 것이 좋습니다.
      • isolatedModules를 활성화하면, 단일 변환 프로세스(single-file transpilation process)에서 올바르게 해석할 수 없는 코드를 작성할 때 TypeScript가 경고를 줍니다.



13.8 JavaScript

  • TypeScript는 기본적으로 .js 또는 .jsx 확장자를 가진 파일을 무시하지만, allowJscheckJs 컴파일러 옵션을 사용하면 JavaScript 파일을 읽고, 컴파일하고, 제한된 기능이지만 타입 검사도 할 수 있습니다.

13.8.1 allowJs

  • allowJs 컴파일러 옵션은 JavaScript 파일에 선언된 구문을 TypeScript 파일에서 타입 검사를 하도록 허용합니다.
    • jsx 컴파일러 옵션과 결합하면 .jsx 파일도 검사할 수 있습니다.
// index.ts
import { value } from "./values";

console.log(`Quote: '${value.toUpperCase()}'`);
// values.js
export const value = "We cannot succeed when half of us are held back.";
  • allowJs를 활성화하지 않으면 import 문은 알려진 타입을 갖지 못합니다.

    • 기본적으로 암시적 any가 되거나 "Could not find a declaration file for module './values'."와 같은 타입 오류가 발생합니다.
  • allowJs는 ECMAScript target에 맞게 컴파일되고 JavaScript로 내보내진 파일 목록에 JavaScript 파일을 추가합니다.

  • allowJs 옵션이 활성화된 경우 소스 맵과 선언 파일도 생성됩니다.

tsc --allowJs
// tsconfig.json
{
  "compilerOptions": {
    "allowJs": true
  }
}
  • 위 예제 코드에서 allowJs 활성화되면 value는 string 타입이 됩니다.

13.8.2 checkJs

  • checkJs 컴파일러 옵션은 다음 2 가지 용도로 사용됩니다.

    1. allowJs가 true가 아니라면 기본 겂을 true로 설정하기
    2. .js와 .jsx 파일에서 타입 검사기 활성화하기
  • checkJs를 활성화하면 TypeScript가 JavaScript 파일을 TypeScript 관련 구문이 없는 TypeScript 파일인 것처럼 처리합니다.

    • 타입 불일치, 철자가 틀린 변수명 등 TypeScript 파일에서 일반적으로 발생하는 모든 오류를 발생시킬 수 있습니다.
tsc --checkJs
// tsconfig.json
{
  "compilerOptions": {
    "checkJs": true
  }
}
  • checkJs가 활성화되면 다음 JavaScript 파일은 잘못된 변수명에 대한 타입 오류가 발생합니다.
// index.js
let myQuote = "Each person must live their life as a model for others.";

console.log(quote);
// Error: Cannot find name 'quote'. Did you mean 'myQuote'?
  • checkJs가 활성화되지 않았다면 TypeScript는 해당 버그에 대한 오류를 보고하지 않습니다.

@ts-check

  • 파일 상단에 // @ts-check 주석을 사용해 파일별로 checkJs를 활성화합니다.
    • 이 작업으로 해당 JavaScript 파일에 대해서만 checkJs 옵션이 활성화됩니다.
// index.js
// @ts-check
let myQuote = "Each person must live their life as a model for others.";

console.log(quote);
// Error: Cannot find name 'quote'. Did you mean 'myQuote'?

13.8.3 JSDoc Support

  • allowJscheckJs가 활성화되면 TypeScript는 코드의 모든 JSDocs 정의를 인식합니다.

  • 다음 코드에서 string 타입을 받는 sentenceCase 함수에 대한 JSDoc을 선언하고, allowJscheckJs를 활성화합니다.

    • TypeScript는 해당 함수의 매개변수 타입이 string이라는 것을 인식하고, 반환 타입이 string이라는 것을 유추합니다.
    • TypeScript는 string[] 인수에 대한 타입 오류가 보고합니다.
// index.js

/**
* @param {string} text
*/
function sentenceCase(text) {
  return `${text[0].toUpperCase()} ${text.slice(1)}`;
}

sentenceCase("hello world"); // Ok

sentenceCase(["hello", "world"]);
// Error: Argument of type 'string[]' is not assignable to parameter of type 'string'.
  • TypeScript의 JSDoc 지원은 시간이 충분하지 않은 프로젝트나 TypeScript로 변환하는데 익숙하지 않은 개발자를 위해 타입 검사를 점진적으로 추가하는데 유용합니다.



13.9 Configuration Extensions

  • TypeScript는 구성 파일을 JavaScript로 작성하거나 import 또는 require 사용을 허용하지 않지만, TSConfig 파일이 다른 구성 파일에서 구성 값을 확장하거나 복사하도록 선택하는 메커니즘을 제공합니다.

13.9.1 extends

  • TSConfig는 extends 구성 옵션을 사용해 다른 TSConfig에서 확장할 수 있습니다.

  • extends는 다른 TSConfig 파일에 대한 경로를 가져오고 해당 파일의 모든 설정을 복사해야 함을 나타냅니다.

    • extends 구성 옵션은 클래스의 extends 키워드와 유사하게 작동합니다.
    • 파생 또는 자식 구성에서 선언된 모든 옵션은 기본 또는 부모 구성에서 동일한 이름의 모든 옵션을 다시 정의합니다.
  • 예를 들어 여러 개의 packages/* 디렉터리를 포함하는 모노레포처럼 여러 개의 TSConfig가 있는 많은 저장소는 확장할 tsconfig.json 파일에 대한 tsconfig.base.json 파일을 생성합니다.

// tsconfig.base.json
{
  "complierOptions": {
    "strict": true
  }
}
// packages/core/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "includes": ["src"]
}
  • complierOptions는 재귀적으로 고려됩니다.

    • 파생된 TSConfig에서 특정 옵션을 재정의하지 않는 한 기본 TSConfig의 각 컴파일러 옵션은 파생된 TSConfig로 그대로 복사됩니다.
  • allowJs 옵션을 추가하는 파생된 TSConfig는 여전히 기본 TSConfig의 컴파일러 옵션인 complierOptions.strict가 true로 설정됩니다.

// packages/core/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "complierOptions": {
    "allowJs": true
  },
  "includes": ["src"]
}

확장 모듈

  • extends 속성은 다음 JavaScript 가져오기 중 하나를 사용합니다.

    • 절대 경로(absolute path) : @ 또는 알파벳 문자로 시작하는 경로
    • 상대 경로(relative path) : 마침표(.)로 시작하는 로컬 파일 경로
  • extends 값이 절대 경로라면 npm 모듈에서 TSConfig를 확장함을 나타냅니다.

    • TypeScript는 이름과 일치하는 패키지를 찾기 위해 일반 노드 모듈 확인 시스템을 확인합니다.
  • 해당 패키지의 package.json은 상대 경로 문자열이 있는 "tsconfig" 필드를 포함하고, 해당 경로의 TSconfig 파일이 사용됩니다.

    • 그렇지 않으면 패키지의 tsconfig.json 파일이 사용됩니다.
  • 많은 조직에서 npm 패키지을 사용해 여러 저장소 또는 모노레포 내에서 TypeScript 컴파일러 옵션을 표준화합니다.

  • 다음 TSConfig 파일은 @my-org 조직의 모노레포에 대해 설정하는 파일입니다.

    • packages/js는 allowJs 컴파일러 옵션을 지정해야 하지만 packages/ts는 어떠한 컴파일러 옵션도 변경하지 않습니다.
// packages/tsconfig.json
{
  "complierOptions": {
    "strict": true
  }
}
// packages/js/tsconfig.json
{
  "extends": "@my-org/tsconfig",
  "complierOptions": {
    "strict": true
  }, 
  "includes": ["src"]
}
// packages/ts/tsconfig.json
{
  "extends": "@my-org/tsconfig", 
  "includes": ["src"]
}

13.9.2 Configuration Bases

  • 처음부터 고유한 구성을 생성하거나 --init 제안을 하는 대신, 특정 런타임 환경에 맞게 미리 만들어진 base TSConfig 파일로 시작할 수 있습니다.

    • 미리 만들어진 base TSConfig 파일은 @tsconfig/recommended 또는 @tsconfig/node16 같은 @tsconfig/ 아래의 npm registry에서 사용할 수 있습니다.
  • 예를 들어 deno에서 권장하는 base TSConfig 파일을 설치하려면 다음과 같이 진행합니다.

npm install --save-dev @tsconfig/deno
# or
yarn add --dev @tsconfig/deno
  • 구성 베이스 패키지가 설치되고 나면 다른 npm 패키지 구성 확장처럼 참조할 수 있습니다.
{
  "extends": "@tsconfig/deno/tsconfig.json"
}



13.10 Project References

  • 대규모 프로젝트에서 프로젝트의 서로 다른 영역에 서로 다른 구성 파일을 사용하는 것이 유용할 수 있습니다.

  • TypeScript에서는 여러 개의 프로젝트를 함께 빌드하는 프로젝트 레퍼런스(project reference) 시스템을 정의할 수 있습니다.

  • 프로젝트 레퍼런스 설정 작업은 단일 TSConfig 파일을 사용하는 것보다 조금 더 작업이 많지만 몇 가지 핵심 이점이 있습니다.

    • 특정 코드 영역에 대해 다른 컴파일러 옵션을 지정할 수 있습니다.
    • TypeScript는 개별 프로젝트에 대한 빌드 출력을 캐시할 수 있으므로 종종 대규모 프로젝트의 빌드 시간이 훨씬 빨라집니다.
    • 프로젝트 레퍼런스는 코드의 개별 영역을 구조화하는 데 유용한 의존성 트리(dependency tree, 특정 프로젝트가 특정 다른 프로젝트에서 파일을 가져오는 것만 허용)를 실행합니다.
  • 프로젝트 레퍼런스를 활성화하기 위해 프로젝트 설정을 구축하는 방법을 소개합니다.

    • TSConfig의 composit 모드는 다중 TSConfig 빌드 모드에 적합한 방식으로 작동하도록 강제합니다.
    • TSConfig의 references는 TSConfig가 의존하는 복합 TSConfig를 나타냅니다.
    • 빌드 모드는 복합 TSConfig reference를 사용하여 파일 빌드를 조정합니다.

13.10.1 composite

  • TypeScript는 프로젝트에서 composite 구성 옵션을 선택해 파일 시스템 입력과 출력이 제약 조건을 준수함을 나타냅니다.

    • 이 과정을 통해 빌드 도구가 빌드 입력과 비교해 빌드 출력이 최신 상태인지 여부를 쉽게 확인할 수 있습니다.
  • composite이 true일 때는 다음과 같습니다.

    • rootDir 설정이 아직 명시적으로 설정되지 않았다면 기본적으로 TSConfig 파일이 포함된 디렉터리로 설정됩니다.
    • 모든 구현 파일은 includes 패턴이 일치하거나 files 배열에 나열되어야 합니다.
    • declaration 컴파일러 옵션의 기본값은 true입니다.
  • 다음 코드는 core/ 디렉터리에서 composite 모드를 활성화하기 위한 모든 조건과 일치합니다.

// core/tsconfig.json
{
  "complierOptions": {
    "declaration": true
  },
  "composite": true
}
  • 이러한 변경은 TypeScript가 프로젝트에 대한 모든 입력 파이과 일치하는 .d.ts 파일을 생성하도록 강제할 때 유용합니다.
  • composite 옵션은 references 구성 옵션과 함께 사용할 때 가장 유용합니다.

13.10.2 references

  • TypeScript 프로젝트는 TSConfig에 references 설정이 있는 복합 TypeScript 프로젝트에서 생성된 출력에 의존함을 나타낼 수 있습니다.

    • 참조된 프로젝트에서 모듈을 가져오는 것은 출력 .d.ts 선언 파일에서 가져오는 것으로 타입 시스템에 표시됩니다.
  • 다음 코드는 /core 디렉터리를 입력으로 참조하도록 shell/ 디렉터리를 설정합니다.

// shell/tsconfig.json
{
  "references": [
    { "path": "../core" }
  ]
}

Note

  • references 구성 옵션은 기본 TSConfig 옵션에서 extends를 통해 파생된 TSConfig로 복사되지 않습니다.
  • references 옵션은 빌드 모드와 함께 사용할 때 가장 유용합니다.

13.10.3 Build Mode

  • 코드 영역이 프로젝트 레퍼런스를 사용할 수 있도록 한번 설정되면 빌드(build) 모드에서 -b 또는 --b CLI 플래그를 통해 tsc를 사용할 수 있습니다.

    • 빌드 모드는 tsc를 프로젝트 빌드 코디네이터(cordinator) 같은 것으로 향상시킵니다.
    • 이를 통해 tsc는 내용과 파일 출력이 마지막으로 생성된 시간을 기준으로 마지막 빌드 이후 변경된 프로젝트만 다시 빌드합니다.
  • TypeScript의 빌드 모드는 TSConfig가 제공될 때 다음 내용을 수행합니다.

    1. TSConfig의 참조된 프로젝트를 찾습니다.
    2. 최신 상태인지 감지합니다.
    3. 오래된 프로젝트를 올바른 순서로 빌드합니다.
    4. 제공된 TSConfig 또는 TSConfig의 의존성이 변경된 경우 빌드합니다.
  • TypeScript 빌드 모드 기능은 최신 프로젝트를 다시 빌드하는 것을 건너뛰도록 해 빌드 성능을 크게 향상시킵니다.

코디네이터 구성

  • 저장소에서 TypeScript 프로젝트 레퍼런스를 설정하는 편리한 방법은 빈 파일 배열과 저장소의 모든 프로젝트 레퍼런스에 대한 레퍼런스를 사용해 최상위 레벨의 tsconfig.json을 설정하는 것입니다.

    • 최상위 TSConfig는 TypeScript가 파일 자체를 빌드하도록 지시하지 않습니다.
    • 대신 필요에 따라 참조된 프로젝트를 빌드하도록 TypeScript에 알리는 역할만 합니다.
  • 다음 tsconfig.json은 저장소의 packages/core와 packages/shell 프로젝트를 빌드하는 것을 나타냅니다.

// tsconfig.json
{
  "files": [],
  "references": [
    { "path": "./packages/core" },
    { "path": "./packages/shell" }
  ]
}
  • package.json 안에 tsc -b를 바로 호출하는 build 또는 complie이라는 이름의 스크립트를 표준화해서 사용할 수 있습니다.
// package.json
{
  "scripts": {
    "build": "tsc -b"
  }
}

빌드 모드 옵션

  • 빌드 모드는 몇 가지 빌드에 특화된 CLI 옵션을 지원합니다.

    • --clean : 지정된 프로젝트의 출력을 삭제합니다. (--dry와 함께 사용할 수 있습니다)
    • --dry : 수행할 작업을 보여주지만 실제로는 아무것도 빌드하지 않습니다.
    • --force : 모든 프로젝트가 오래된 것처럼 작동합니다.
    • -w 또는 --watch : 일반적으로 TypeScript의 watch 모드와 유사합니다.
  • 빌드 모드는 watch 모드를 지원하기 때문에 tsc b -w 같은 명령을 실행하면 대규모 프로젝트에서 모든 컴파일러 오류에 대한 최신 목록을 빠르게 확인할 수 있습니다.

0개의 댓글