[TypeScript 독학] #6 tsconfig.json, etc

안광의·2022년 3월 5일
0

TypeScript 독학

목록 보기
6/12
post-thumbnail

시작하며

이번에는 타입스크립트 설정 파일인 tsconfig.json와 실제 개발을 진행할때 알아야 하는 내용을 정리해보려고 한다. 타입스크립트는 자바스크립트로 변환하는 과정을 거치기 때문에 사용자의 설정에 따라 여러 옵션들을 변경할 수 있다. 자바스크립트로 개발된 프로젝트를 변환하는 과정에 중요한 내용이기 때문에 최대한 자세하게 정리하려고 한다.


tsconfig.json

타입스크립트 설치

$ npm install -g typescript

tsc 명령어

$ tsc app.ts

tsc 명령어는 타입스크립트를 자바스크립트로 변환할 때 사용하는 명령어로 위와 같이 입력하면 app.ts 파일이 app.js로 변환된다.

tsc 명령어를 대상 파일을 지정하지 않고 실행하면 현재 폴더에 있는 타입스크립트 설정 파일을 기준으로 변환 작업을 수행한다. 만약 현재 폴더에 타입스크립트 설정 파일이 없다면 프로젝트 폴더 내에서 상위 폴더의 경로를 검색해 나간다.

tsconfig.json 파일 생성

$ tsc --init

타입스크립트를 전역으로 설치하고 tsc --init를 입력하면 컴파일 옵션에 포함되어져 있는 옵션들에 대한 주석이 달려있는 tsconfig.json 파일이 생성된다.

{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig.json to read more about this file */

    /* Projects */
    // "incremental": true,                              /* Enable incremental compilation */
    // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
    // "tsBuildInfoFile": "./",                          /* Specify the folder for .tsbuildinfo incremental compilation files. */
    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects */
    // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
    // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */

    /* Language and Environment */
    "target": "es2016",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
    // "lib": [],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
    // "jsx": "preserve",                                /* Specify what JSX code is generated. */
    // "experimentalDecorators": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */
    // "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
    // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
    // "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
    // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
    // "reactNamespace": "",                             /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
    // "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
    // "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */

    /* Modules */
    "module": "commonjs",                                /* Specify what module code is generated. */
    // "rootDir": "./",                                  /* Specify the root folder within your source files. */
    // "moduleResolution": "node",                       /* Specify how TypeScript looks up a file from a given module specifier. */
    // "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
    // "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
    // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
    // "typeRoots": [],                                  /* Specify multiple folders that act like `./node_modules/@types`. */
    // "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */
    // "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
    // "resolveJsonModule": true,                        /* Enable importing .json files */
    // "noResolve": true,                                /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */

    /* JavaScript Support */
    // "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
    // "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */
    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */

    /* Emit */
    // "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
    // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
    // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
    // "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
    // "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
    // "outDir": "./",                                   /* Specify an output folder for all emitted files. */
    // "removeComments": true,                           /* Disable emitting comments. */
    // "noEmit": true,                                   /* Disable emitting files from a compilation. */
    // "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
    // "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types */
    // "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
    // "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
    // "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */
    // "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
    // "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
    // "newLine": "crlf",                                /* Set the newline character for emitting files. */
    // "stripInternal": true,                            /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
    // "noEmitHelpers": true,                            /* Disable generating custom helper functions like `__extends` in compiled output. */
    // "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
    // "preserveConstEnums": true,                       /* Disable erasing `const enum` declarations in generated code. */
    // "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */
    // "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */

    /* Interop Constraints */
    // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
    // "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
    "esModuleInterop": true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
    // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
    "forceConsistentCasingInFileNames": true,            /* Ensure that casing is correct in imports. */

    /* Type Checking */
    "strict": true,                                      /* Enable all strict type-checking options. */
    // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied `any` type.. */
    // "strictNullChecks": true,                         /* When type checking, take into account `null` and `undefined`. */
    // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
    // "strictBindCallApply": true,                      /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
    // "strictPropertyInitialization": true,             /* Check for class properties that are declared but not set in the constructor. */
    // "noImplicitThis": true,                           /* Enable error reporting when `this` is given the type `any`. */
    // "useUnknownInCatchVariables": true,               /* Type catch clause variables as 'unknown' instead of 'any'. */
    // "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
    // "noUnusedLocals": true,                           /* Enable error reporting when a local variables aren't read. */
    // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read */
    // "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
    // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
    // "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
    // "noUncheckedIndexedAccess": true,                 /* Include 'undefined' in index signature results */
    // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
    // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type */
    // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
    // "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */

    /* Completeness */
    // "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
    "skipLibCheck": true                                 /* Skip type checking all .d.ts files. */
  }
}

모든 옵션을 정리할 필요도 없고 주석도 달려 있기 때문에 주요 옵션들에 대해서 정리하려고 한다.

TOP LEVEL

  • files
{
  "files": ["app.ts", "./utils/math.ts"]
}

  • include
{
  "include": ["src/**/*"]
}

files와 같이 파일을 개별로 지정하지 않고 include 옵션으로 변환할 폴더를 지정할 수 있다.

#### 와일드 카드 패턴
* : 해당 디렉토리의 모든 파일 검색
? : 해당 디렉토리 안에 파일의 이름 중 한 글자라도 맞으면 해당
** : 하위 디렉토리를 재귀적으로 접근(하위 디렉토리의 하위 디렉토리가 존재하는 경우 반복해서 접근)

  • extends
    특정 타입스크립트 설정 파일에서 다른 타입스크립트 설정의 내용을 가져와 추가할 수 있는 속성이다.
// config/base.json
{
  "compilerOptions": {
    "noImplicitAny": true
  }
}
// tsconfig.json
{
  "extends": "./config/base"
}

compilerOptions

  • typeRoots

타입스크립트 설정 파일은 기본적으로 node_modules를 제외하지만 써드 파티 라이브러리의 타입을 정의해놓는 @types 폴더는 컴파일에 포함한다. 여기서 만약 @types의 기본 경로를 변경하고 싶다면 아래와 같이 지정할 수 있다.

{
  "compilerOptions": {
    "typeRoots" : ["./my-types"]
  }
}

  • outDir : filesinclude를 통해서 선택된 파일들의 결과문이 저장되는 디렉터리를 outDir을 통해서 지정할 수 있다.
{
  "compilerOptions": {
    "outDir": "./build/",
  }
}

  • baseUrl: 외부 모듈이 아닌 이상 상대 경로로 모듈을 참조해야 한다. baseUrl은 외부 모듈이 아닌 모듈들을 절대 경로 참조할 수 있게 해 준다. 만약 baseUrlsrc로 설정하게 되면 src/를 기준으로 절대 경로로 모듈 참조가 가능해진다.

  • paths
    모듈 참조를 baseUrl를 기준으로 다시 매핑시킬 수 있다.

{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
        "app/*": ["app/*"],
        "config/*": ["app/_config/*"],
        "lib/*": ["lib/*"],
        "tests/*": ["tests/*"]
    },
}

baseUrl을 지정하는 것만으로 절대 경로로 모듈 참조를 할 수 있지만 더 상세하게 일을 지어줄 수 있게 된다. 이를 통해서 "../../../lib/some"과 같이 길고 알아보기 힘든 경로를 "lib/some"과 같이 단순하게 만들 수 있게 된다.


  • sourceMap : 디버깅을 위해 소스맵 파일을 생성할지 안할지에 대한 옵션이다.

  • noImplicitAny : 타입을 any타입으로 지정하였을 때, 오류가 발생할지 안할지에 대한 옵션이다.

  • module : 생성될 모듈의 형식을 지정해준다. 종류에는 none, commonjs, amd, es5, es6, es7 ... 등이 있다. ESNext라고 지정할 경우 현재 시점의 가장 최신 버전인 es버전으로 지정한다.

  • target : 컴파일될 파일의 형식을 지정해준다. 종류에는 es3, es5, es6, es7 ... 등이 있다. - ESNext라고 지정할 경우 현재 시점의 가장 최신 버전인 es버전으로 지정한다.

  • lib
    타입스크립트 파일을 자바스크립트로 컴파일 할 때 포함될 라이브러리의 목록이며, 대표적으로 async 코드를 컴파일 할 때 Promise 객체가 필요하므로 아래와 같은 설정을 해줘야 한다. 여기서 es2015는 프로미스 객체를 타입스크립트에서 인식할 수 있게 필요한 속성이고, dom 관련 속성은 DOM API를 사용하는 경우 필요하다.
{
  "lib": ["es2015", "dom", "dom.iterable"]
}

  • jsx : 리액트의 jsx 문법을 컴파일하기 위해 제공되는 옵션이다. 출력 단계에서 영향을 끼치지만 타입 검사를 진행할 때는 영향을 끼치지 않는 옵션이다. 옵션의 종류에는 preserve, react-jsx, react-native 등이 있다.

  • allowJs : 타입스크립트 컴파일 작업을 진행할 때 자바스크립트 파일도 포함될 수 있는지를 설정해주는 속성으로 이미 기존에 존재하는 자바스크립트 프로젝트에 타입스크립트를 점진적으로 적용할 때 사용한다.




@types 라이브러리

자바스크립트로 만들어진 써드 파티 라이브러리(jQuery, lodash, chart 등)를 타입스크립트에서 사용하려면 각 기능에 대한 타입이 정의되어 있어야 하기 때문에 타입스크립트에서 제대로 동작하지 않는다.

이런 경우에는 @types/라는 별칭으로 시작하는 라이브러리를 설치해야한다.

$ npm install @types/react

@types 라이브러리가 없는 경우

타입스크립트를 지원하지 않는 라이브러리는 아래 방법을 사용할 수 있다.

1. tsconfig.json에 아래와 같이 typeRoots와 declaration, declarationDir 등을 설정한다.

{
  "compilerOptions": {
    ...
    "typeRoots": ["./types", "./node_modules/@types"], // 보통 types 폴더를 만들어 타입 정의
    "declaration": true, // lib 만들 때 .d.ts 파일을 자동으로
    "declarationDir": "./types" // 이 폴더에 만들어주는 옵션
  },
  "typeRoots": ["./types", "./node_modules/@types"],
  "include": ["src"]
}

2. root에서 types 라는 폴더를 생성

3. type이 없던 외부 라이브러리의 이름으로 폴더를 하나 생성

4. 폴더 아래 index.d.ts 생성

5. index.d.ts에 직접 타입을 정의하거나 아래와 같이 적어주면 사용이 가능하다.

declare module '모듈 이름'` 



ETC

d.ts 파일

타입스크립트 선언 파일 d.ts는 타입스크립트 코드의 타입 추론을 돕는 파일이다. 예를 들어, 전역 변수로 선언한 변수를 특정 파일에서 import 구문 없이 사용하는 경우 해당 변수를 인식하지 하는데, 아래와 같이 해당 변수를 선언해서 에러가 나지 않게 할 수 있다.

declare const global = 'sth';

전역 변수와 전역 함수에 대한 타입 선언

해당 타입스크립트 파일에서 사용할 순 있지만 선언되어 있지 않은 전역 변수나 전역 함수는 아래와 같이 타입을 선언할 수 있다.

// 전역 변수
declare const pi = 3.14;

// 전역 함수
declare namespace myLib {
  function greet(person: string): string;
  let name: string;
}
myLib.greet('캡틴');
myLib.name = '타노스';

유틸리티 타입

유틸리티 타입은 이미 정의해 놓은 타입을 변환할 때 사용하기 좋은 타입 문법으로 훨씬 더 간결한 문법으로 타입을 정의할 수 있다.

Partial

파셜(Partial) 타입은 특정 타입의 부분 집합을 만족하는 타입을 정의할 수 있다.

interface Address {
  email: string;
  address: string;
}

type MayHaveEmail = Partial<Address>;
const me: MayHaveEmail = {}; // 가능
const you: MayHaveEmail = { email: 'test@abc.com' }; // 가능
const all: MayHaveEmail = { email: 'capt@hero.com', address: 'Pangyo' }; // 가능

Pick

픽(Pick) 타입은 특정 타입에서 몇 개의 속성을 선택(pick)하여 타입을 정의할 수 있다.

interface Hero {
  name: string;
  skill: string;
}
const human: Pick<Hero, 'name'> = {
  name: '스킬이 없는 사람',
};
type HasThen<T> = Pick<Promise<T>, 'then' | 'catch'>;
let hasThen: HasThen<number> = Promise.resolve(4);
hasThen.th // 위에서 'then'만 선택하면 'then'만 제공, 'catch' 선택하면 'catch만 제공'

Omit

오밋(Omit) 타입은 특정 타입에서 지정된 속성만 제거한 타입을 정의해 준다.

interface AddressBook {
  name: string;
  phone: number;
  address: string;
  company: string;
}
const phoneBook: Omit<AddressBook, 'address'> = {
  name: '재택근무',
  phone: 12342223333,
  company: '내 방'
}
const chingtao: Omit<AddressBook, 'address'|'company'> = {
  name: '중국집',
  phone: 44455557777
}



마치며

타입스크립의 기본적인 부분은 정리했지만 아직 부족한 부분이 많고 실제 개발을 진행한 것이 아니기 때문에 타입스크립트를 기술스택에 적기에는 무리가 있다. react+js로 제작한 이력서 페이지는 타입스크립트로 변환해보았지만 라이브러리나 react의 다양한 hook을 사용하지 않은 간단한 프로젝트여서 가장 최근에 진행한 개인 프로젝트인 페이크서치를 타입스크립트로 바꾸면서 블로그에 작성한 내용을 보완해보려고 한다. 또 최근 Next.js에 관심이 생겨서 가능하다면 Next.js+typescript로 SSR을 구현해볼 생각이다.

profile
개발자로 성장하기

0개의 댓글