04.TS Complier

Updated:


TS Complier

1.Compilation Context

from TypeScrupt Deep Dive

  • The compilation context is basically just a fancy term for grouping of the files that TypeScript will parse and analyze to determine what is valid and what isn’t.

  • Along with the information about which files, the compilation context contains information about which compiler options are in use

  • A great way to define this logical grouping (we also like to use the term project) is using a tsconfig.json file.

  • 즉, 요약하자면 Compliation context 는 파일을 그룹핑 하는데 어떠한 방식으로 사용할것인지 맥락을 의미하며, 그런것은 tsconfig.json 에 적혀있게 됩니다

image

2.tsconfig schema

http://json.schemastore.org/tsconfig 에서 전체적인 schema 를 볼수 있습니다.

최상위 프로퍼티

  • compileOnSave

  • extends

  • compileOptions

  • files

  • include

  • references

🔶 tsconfig.json 파일 생성

# Ubuntu 환경에서 작성하였습니다.

$ mkdir comilation-context  # test 할 임의 폴더 생성
$ cd comilation-context/ # 폴더로 이동
$ npm init -y # package.json 생성
$ npm i typescript -D # 개발자의존성 typescript 인스톨
$ npx tsc --init # 기본 생성으로 tsconfig.json 파일 생성

3.complieOnSave

from schema

    "compileOnSaveDefinition": {
      "properties": {
        "compileOnSave": {
          "description": "Enable Compile-on-Save for this project.",
          "type": "boolean"
        }
      }

KakaoTalk_20210508_094902955

  • true / false (default false)

🔑 true 로 해놓으면 저장과 동시에 자동으로 compile 해주는 옵션입니다.

  • 이것을 해주는것은 IDE (VS code, atom 등)에서 동작을 실행해줍니다.

    • Visual Studio 2015 with TypeScirpt 1.8.4 이상

    • atom-typescript 플러그인

4.extends

  • 다른 파일을 상속 받고, 그안에 뭔가 추가해서 사용하는 옵션입니다.

from schema

    "extendsDefinition": {
      "properties": {
        "extends": {
          "description": "Path to base configuration file to inherit from. Requires TypeScript version 2.1 or later.",
          "type": "string"
        }
      }
    },
  • 파일 (상대) 경로명: string
// in PROJECT/base.json
{
  "comilerOptions": {
    "strict": true
  }
}

// in PROJECT/tsconfig.json
{
  "extends": "./base.json",
}

TS 에서 공식으로 여러가지 형태의 상속할 수 있는 부모설정 등을 알려주는 Office 사이트 https://github.com/tsconfig/bases

  • 예를 들어 node 도 사용할 수 있는데 node runtime 버전마다 다른 설정들을 가져와서 써야함

🔷 예시

$ npm install --save-dev @tsconfig/deno
  • 설치 후에 tsconfig.json 파일에서 extends 에다가 여러가지 형태의 증명된 상속 파일을 추가 할 수 있는 것임
{
  "extends": @tsconfig/deno/tsconfig.json
}

5.files, include, exclude

  • 위의 3가지를 통해서 내 프로젝트 안에 어떤 파일을 컴파일 한건지를 결정하게 됩니다.

from schema

    "filesDefinition": {
      "properties": {
        "files": {
          "description": "If no 'files' or 'include' property is present in a tsconfig.json, the compiler defaults to including all files in the containing directory and subdirectories except those specified by 'exclude'. When a 'files' property is specified, only those files and those specified by 'include' are included.",
          "type": "array",
          "uniqueItems": true,
          "items": {
            "type": "string"
          }
        }
      }
    },
    "excludeDefinition": {
      "properties": {
        "exclude": {
          "description": "Specifies a list of files to be excluded from compilation. The 'exclude' property only affects the files included via the 'include' property and not the 'files' property. Glob patterns require TypeScript version 2.0 or later.",
          "type": "array",
          "uniqueItems": true,
          "items": {
            "type": "string"
          }
        }
      }
    },
    "includeDefinition": {
      "properties": {
        "include": {
          "description": "Specifies a list of glob patterns that match files to be included in compilation. If no 'files' or 'include' property is present in a tsconfig.json, the compiler defaults to including all files in the containing directory and subdirectories except those specified by 'exclude'. Requires TypeScript version 2.0 or later.",
          "type": "array",
          "uniqueItems": true,
          "items": {
            "type": "string"
          }
        }
      }
    },
  • 📌 셋다 설정이 없으면, 전부다 컴파일 합니다

  • files

    • 상대 혹은 절대 경로의 리스트 배열입니다.

    • exclude 보다 우선순위 입니다.

  • include, exclude

    • golb 패턴 (.gitignore 와 비슷합니다)

    • include

      • exclude 보다 약합니다.

        • 같은걸 사용하면, .ts / .tsx / .d.ts 만 include 합니다. (allowJS)
    • excude

      • 🔑 설정 안하면 4가지(node_modules, bower_compenents, jspam_package, ) 을 default 로 제외합니다.

      • 은 항상 제외합니다. (include 에 있어도..)

6.complieOptions - typeRoots, types

  • 프로젝트에서 라이브러리를 사용할때, 대부분 JS 이기 때문에 type 이 없는 경우가 많이 있습니다

  • 그래서, TS 에서 Type 지정해주기 위해 사용합니다. (특히, JS library 중 제일 많이 쓰이는 react 사용할 때 꼭 필요함..)

📌 예제

  • npm -i react 를 설치하고 react 를 사용할 때 나타 나는 error

스크린샷, 2021-05-10 16-27-26

from schema

"typeRoots": {
  "description": "Specify multiple folders that act like `./node_modules/@types`.",
  "type": "array",
  "uniqueItems": true,
  "items": {
    "type": "string"
  },
  "markdownDescription": "Specify multiple folders that act like `./node_modules/@types`.\n\nSee more: https://www.typescriptlang.org/tsconfig#typeRoots"
},
"types": {
  "description": "Specify type package names to be included without being referenced in a source file.",
  "type": "array",
  "uniqueItems": true,
  "items": {
    "type": "string"
  },
  • npm i --save-dev @types/react 를 설치하게 되면, node_modules 폴더 안에 @types 폴더 안에 react 라는 폴더가 생성 됩니다

  • index.d.ts 파일에 설정 파일을 통해서 importReacttype definition 으로 사용되게 됩니다.

  • 단, 유명하지 않거나, 내가 작성한 module 은 위의 방법으로 지원하지 않기 때문에 @types 에 같이 작성해서 사용하는 것이 typeRoots 방법임

@types

  • Specicity type package name 을 가리킴 (예, react )

  • TypeScript 2.0 부터 사용 가능해진 내장 type definition 시스템

  • 아무 설정을 안하면?

    • node_modules/@types 라는 모든 경로를 찾아서 사용합니다.
  • typeRoots 를 사용하면?

    • 배열 안에 들어있는 경로들 아래서만 가져옵니다. (multiful 로 사용이 가능하다는것)
  • type 을 사용하면?

    • 배열 안의 모듈 혹은 ./node_modules/@types 안의 모듈 이름에서 찾아 옵니다.

    • [] 빈 배열을 넣는다는건 이 시스템을 이용하지 않겠다는 것입니다.

  • 📌 TypeRoots 와 type 를 같이 사용하지 않습니다.

7.complieOptions - target, lib

  • 프로젝트 설정에 기본이 되고 중요한 설정입니다.

- target

from Schema

"target": {
  "description": "Set the JavaScript language version for emitted JavaScript and include compatible library declarations.",
  "type": "string",
  "default": "ES3",
  "anyOf": [{
      "enum": [
        "ES3",
        "ES5",
        "ES6",
        "ES2015",
        "ES2016",
        "ES2017",
        "ES2018",
        "ES2019",
        "ES2020",
        "ESNext"
      ]
    },
    {
      "pattern": "^([Ee][Ss]([356]|(20(1[56789]|20))|[Nn][Ee][Xx][Tt]))$"
    }
  ],
  "markdownDescription": "Set the JavaScript language version for emitted JavaScript and include compatible library declarations.\n\nSee more: https://www.typescriptlang.org/tsconfig#target"
  • 예를 들어, arrow function 을 사용해서 ts 를 complie 해서 js 로 변환 할때

    • es5 로 target 시 function 으로 변환 되서 complie 됨

    • es6 로 target 시 arrow 함수 기능을 지원하는 ECMA 이기에 js 파일에 그대로 arrow 함수가 compile 되서 나타남

- lib

  • TS 가 설치가 될때, 기본적으로 bundled 된 library 중에서 어떤 것을 setting 해서 쓸건지 정하는 옵션입니다.
"lib": {
  "description": "Specify a set of bundled library declaration files that describe the target runtime environment.",
  "type": "array",
  "uniqueItems": true,
  "items": {
    "type": "string",
    "anyOf": [{
        "enum": [
          "ES5",
          "ES6",
          "ES2015",
          "ES2015.Collection",
          "ES2015.Core",
          "ES2015.Generator",
          "ES2015.Iterable",
          "ES2015.Promise",
          "ES2015.Proxy",
          "ES2015.Reflect",
          "ES2015.Symbol.WellKnown",
          "ES2015.Symbol",
          "ES2016",
          "ES2016.Array.Include",
          "ES2017",
          "ES2017.Intl",
          "ES2017.Object",
          "ES2017.SharedMemory",
          "ES2017.String",
          "ES2017.TypedArrays",
          "ES2018",
          "ES2018.AsyncGenerator",
          "ES2018.AsyncIterable",
          "ES2018.Intl",
          "ES2018.Promise",
          "ES2018.Regexp",
          "ES2019",
          "ES2019.Array",
          "ES2019.Object",
          "ES2019.String",
          "ES2019.Symbol",
          "ES2020",
          "ES2020.BigInt",
          "ES2020.Promise",
          "ES2020.String",
          "ES2020.Symbol.WellKnown",
          "ESNext",
          "ESNext.Array",
          "ESNext.AsyncIterable",
          "ESNext.BigInt",
          "ESNext.Intl",
          "ESNext.Promise",
          "ESNext.String",
          "ESNext.Symbol",
          "DOM",
          "DOM.Iterable",
          "ScriptHost",
          "WebWorker",
          "WebWorker.ImportScripts"
        ]
      },
      {
        "pattern": "^[Ee][Ss]5|[Ee][Ss]6|[Ee][Ss]7$"
      },
      {
        "pattern": "^[Ee][Ss]2015(\\.([Cc][Oo][Ll][Ll][Ee][Cc][Tt][Ii][Oo][Nn]|[Cc][Oo][Rr][Ee]|[Gg][Ee][Nn][Ee][Rr][Aa][Tt][Oo][Rr]|[Ii][Tt][Ee][Rr][Aa][Bb][Ll][Ee]|[Pp][Rr][Oo][Mm][Ii][Ss][Ee]|[Pp][Rr][Oo][Xx][Yy]|[Rr][Ee][Ff][Ll][Ee][Cc][Tt]|[Ss][Yy][Mm][Bb][Oo][Ll].[Ww][Ee][Ll][Ll][Kk][Nn][Oo][Ww][Nn]|[Ss][Yy][Mm][Bb][Oo][Ll]))?$"
      },
      {
        "pattern": "^[Ee][Ss]2016(\\.[Aa][Rr][Rr][Aa][Yy].[Ii][Nn][Cc][Ll][Uu][Dd][Ee])?$"
      },
      {
        "pattern": "^[Ee][Ss]2017(\\.([Ii][Nn][Tt][Ll]|[Oo][Bb][Jj][Ee][Cc][Tt]|[Ss][Hh][Aa][Rr][Ee][Dd][Mm][Ee][Mm][Oo][Rr][Yy]|[Ss][Tt][Rr][Ii][Nn][Gg]|[Tt][Yy][Pp][Ee][Dd][Aa][Rr][Rr][Aa][Yy][Ss]))?$"
      },
      {
        "pattern": "^[Ee][Ss]2018(\\.([Aa][Ss][Yy][Nn][Cc][Ii][Tt][Ee][Rr][Aa][Bb][Ll][Ee]|[Ii][Nn][Tt][Ll]|[Pp][Rr][Oo][Mm][Ii][Ss][Ee]|[Rr][Ee][Gg][Ee][Xx][Pp]))?$"
      },
      {
        "pattern": "^[Ee][Ss]2019(\\.([Aa][Rr][Rr][Aa][Yy]|[Oo][Bb][Jj][Ee][Cc][Tt]|[Ss][Tt][Rr][Ii][Nn][Gg]|[Ss][Yy][Mm][Bb][Oo][Ll]))?$"
      },
      {
        "pattern": "^[Ee][Ss]2020(\\.([Bb][Ii][Gg][Ii][Nn][Tt]|[Pp][Rr][Oo][Mm][Ii][Ss][Ee]|[Ss][Tt][Rr][Ii][Nn][Gg]|[Ss][Yy][Mm][Bb][Oo][Ll].[Ww][Ee][Ll][Ll][Kk][Nn][Oo][Ww][Nn]))?$"
      },
      {
        "pattern": "^[Ee][Ss][Nn][Ee][Xx][Tt](\\.([Aa][Rr][Rr][Aa][Yy]|[Aa][Ss][Yy][Nn][Cc][Ii][Tt][Ee][Rr][Aa][Bb][Ll][Ee]|[Bb][Ii][Gg][Ii][Nn][Tt]|[Ii][Nn][Tt][Ll]|[Ss][Yy][Mm][Bb][Oo][Ll]))?$"
      },
      {
        "pattern": "^[Dd][Oo][Mm](\\.[Ii][Tt][Ee][Rr][Aa][Bb][Ll][Ee])?$"
      },
      {
        "pattern": "^[Ss][Cc][Rr][Ii][Pp][Tt][Hh][Oo][Ss][Tt]$"
      },
      {
        "pattern": "^[Ww][Ee][Bb][Ww][Oo][Rr][Kk][Ee][Rr](\\.[Ii][Mm][Pp][Oo][Rr][Tt][Ss][Cc][Rr][Ii][Pp][Tt][Ss])?$"
      }
    ]
  },
  "markdownDescription": "Specify a set of bundled library declaration files that describe the target runtime environment.\n\nSee more: https://www.typescriptlang.org/tsconfig#lib"

📌 target 과 lib

  • target

    • 빌드의 결과물을 어떤 버전으로 할 것이냐를 정하는것 입니다.

    • 지정안하면 default es3 입니다.

  • lib

    • 기본 type definition 라이브러리를 어떤 것을 사용할 것인가를 설정 하는 것입니다.

    • lib 를 지정하지 않을 때,

      • target 이 ‘es3’ 일 경우, default 로 lib.d.ts 를 사용합니다.

      • target 이 ‘es5’ 일 경우, default 로 dom, es5, scripthost 를 사용합니다.

      • target 이 ‘es6’ 일 경우, default 로 dom, es6, dom.iterable, scripthost 를 사용합니다.

    • lib 를 지정하면 그 lib 배열로만 라이브러리 사용합니다.

      • 빈 [] 를 사용하면 ‘no definition found brabra… ‘ 라고 나옵니다.

🔶 target, lib 를 적절히 선택하여 어떤 기능이 어떤 버전에서 지원되는 지 확인 후, 그것에 맞는 적절한 버전을 정해 주어야 합니다.

ECMA script compatibility tabe 보기..

8.complieOptions - outDir, outFile, rootDir

from schema

"outFile": {
  "description": "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.",
  "type": "string",
  "markdownDescription": "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.\n\nSee more: https://www.typescriptlang.org/tsconfig#outFile"
},
"outDir": {
  "description": "Specify an output folder for all emitted files.",
  "type": "string",
  "markdownDescription": "Specify an output folder for all emitted files.\n\nSee more: https://www.typescriptlang.org/tsconfig#outDir"
},
"rootDir": {
  "description": "Specify the root folder within your source files.",
  "type": "string",
  "markdownDescription": "Specify the root folder within your source files.\n\nSee more: https://www.typescriptlang.org/tsconfig#rootDir"
},
  • outDir 을 많이 사용하게 되는데, tsconfig.json 파일에서 "outDir": "./dist" 라고 설정을 해 놓으면 compile 된 파일들이 dist 폴더에 js 파일들을 모아 놓고 compile 하고 싶을 때 많이 사용합니다.

  • rootDir 은 ourDir 시 root 경로를 지정 하고 싶을 때 사용됩니다.

🔑 9.complieOptions - strict

  • 앞으로 모든 작업 할 경우, strict 를 true 로 해놓는것이 기본 설정 입니다.

from schema

 "strict": {
   "description": "Enable all strict type checking options.",
   "type": "boolean",
   "default": false,
   "markdownDescription": "Enable all strict type checking options.\n\nSee more: https://www.typescriptlang.org/tsconfig#strict"
 },
  • 다음과 같은 모든 strict type 체크 옵션을 키는 것이 strict : true 입니다.

    • –noImplicitAny

    • –noImplicitThis

    • –strictNullChecks

    • –strictFunctionTypes

    • –strictPropertyInitialization

    • –strictBindCallApply

    • –alwaysStrict

–noImplicitAny

Raise error on expressions and declarations with an implied any type.

  • 명시적이지 않게 any 타입을 사용하여, 표현식과 선언에 사용하면, 에러를 발생 시킵니다.

스크린샷, 2021-05-10 17-36-26

  • 타입스크립트가 추론을 실패한 경우, any 가 맞으면, any 라고 지정하라.

  • 아무것도 쓰지 않으면, 에러를 발생

  • 이 오류를 해결하면, any 라고 지정되어 있지 않은 경우는 any 가 아닌 것이 됩니다. (타입 추론이 되었으므로..)

supperssImplicitAnyIndexErrors

Suppress –nolmplicitAny errors for indexing objects lacking index signatures. (noImplicitAny 를 사용할 때, 인덱스 객체어 인덱스 signature 가 없는 경우 오류가 발생 하는데 이를 예외 처리 합니다)

in detail noImplicitAny regression in 1.3 #1232

스크린샷, 2021-05-10 17-40-39

  • obj[‘foo’] 로 사용할 때, 인덱스 객체라 판단하여, 타입에 인덱스 시그니처가 없는 경우, 에러를 발생시킵니다.

  • 이때, supperssImplicitAnyIndexErrors 옵션을 사용하면, 이런 경우 예외로 간주하여, 에러를 발생시키지 않습니다.

–noImplicitThis

Raise error on this expressions with an implied any type. (명시적이지 않게 any 타입을 사용하여, this 표현식에 사용하면, 에러를 발생합니다)

스크린샷, 2021-05-10 17-47-32

스크린샷, 2021-05-10 17-50-21

  • 첫번째 매개변수 자리에 this 를 놓고, this 에 대한 타입을 어떤 것이라도 표현하지 않으면, noImplicitAny 가 오류를 발생 시킵니다.

  • JS 에서는 매개변수에 this 를 넣으면, 이미 예약된 키워드라 SyntaxError 를 발생 시킵니다.

  • call /apply /bind 와 같이 this 를 대체 하는 함수 콜을 하는 용도로도 쓰입니다.

  • 그래서 this 를 any 로 명시적으로 지정하는 것을 합리적입니다. (물론 구체적인 사용처가 있는 경우 타입을 표현하기도 합니다.)

스크린샷, 2021-05-10 18-07-51

  • Class 에서는 this 를 사용하면서, noImplicitThis 와 관련한 에러가 나지 않습니다.

  • Class 에서 constructor 를 제외한 맴버 함수의 첫번째 매개변수도 일반 함수와 마찬가지로 this 를 사용할 수 있습니다.

–strictNullChecks

  • 중요한 옵션

In stric null checking mode, the null and undefined values are not in the domain of every type and are only assignable to themselves and any (the one exception being that undefined is also assignable to void)

  • strickNullChecks 모드에서는, null 및 undefined 값이 모든 유형의 도메인에 속하지 않으며, 그 자신을 타입으로 가지거나, any 일 경우에만 할당이 가능합니다.

  • 한자지 예외는 undefined 에 void 할당 가능

스크린샷, 2021-05-11 12-50-12

스크린샷, 2021-05-11 12-50-20

  • strickNullChecks 를 적용하지 않으면,

    • 모든 타입은 null, defuned 값을 가질 수 있습니다.

    • string 으로 타입을 지정해도, null 혹은 undefined 값을 할당할 수 있다는 것입니다.

  • strickNullChecks 를 적용하면,

    • 모든 타입은 null, undefined 값을 가질 수 없고, 가지려면 union type 을 이용해서 직겁 명시 해야 합니다.

    • any 타입은 null 과 undefined 를 가집니다. 예외적으로 void 타입의 경우 undefined 를 가집니다.

  • strickNullChkecs 를 적용하지 않고, 어떤 값이 null 과 undefined 를 가진다는 것을 압묵적으로 인정하고 계속 사용하다보면, 정확히 어떤 타입이 오는지르 ㄹ개발자 스스로가 간과할 수 있습니다.

  • 정말로 null 과 undefined 를 가질 수 있는 경우, 해당 값을 조건부로 제외하고 사용하는 것이 좋습니다.

  • 이 옵션을 켜고 사용하는 경우, 사용하려는 함수를 선언할 때부터 매개변수와 리턴 값에 정확한 타입을 지정하려는 노력을 기울여야 하고, 결국 그렇게 사용할 것입니다.

–strictDunctionTypes

Disable bivariant parameter checking for function types

  • 함수 타입에 대한 bivarant 매개변수 검사를 비활성 합니다.

  • 반환 타입은 공변적(covariant)

  • 인자 타입은 반공변적(contravariant)

  • 그런데 TS 에서 인자타입은 covariant 이면서, contravariant 인게 문제 입니다 !

  • 이 문제를 해결하는 옵션이 strickFunctionTypes

  • 옵션을 켜면, 에러가 안나던걸 에러를 나게 함

스크린샷, 2021-05-11 13-01-25

이전에는 위와 같은 코드는 에러를 발생시키지 않았지만, strickFunctionType 을 키게 되면 에러가 발생 됩니다.

참고: https://www.stephanboyer.com/post/132/what-are-covariance-and-contravariance

–strickPropertyInitialization

Ensure non-undefined class properties are initialized in the constructor.

  • 정의되지 않은 클래스의 속성이 생성자에서 초기화되었는지 확인합니다.

  • 이 옵션을 사용하려면 –strictNullChecks 를 사용하도록 설정해야 합니다.

스크린샷, 2021-05-11 13-07-52

  • constructor 에서 초기 값을 할당한 경우 => 정상으로 됩니다

스크린샷, 2021-05-11 13-09-47

  • constructor 에서 안하는 경우

    • 보통 다른 함수로 initialize 하는 경우 (async 함수)

    • constructor 에는 async 를 사용할 수 없다

스크린샷, 2021-05-11 13-10-57

–strictBindCallApply

Enable stricter checking of the bind call, and apply methods on functions

  • bind, call, apply 에 대한 더 엄격한 검사 수행

    • function 의 내장함수인 bind / call / apply 를 사용할 때, 엄격하게 체크하도록 하는 옵션입니다.

    • bind 는 해당 함수 안에서 사용할 this 와 인자를 설정해주는 역활을 하고, callapply 는 this 와 인자를 설정한 후, 실행까지 합니다.

    • call 과 apply 는 인자를 설정하는 방식에서 차이점이 있습니다.

      • call 은 함수의 인자를 여러인자의 나열로 넣어서 사용하고, apply 는 모든 인자를 배열 하나로 넣어서 사용합니다.

–alwaysStrict

Parde in strict mode and emit “use strict” for each source file

  • 각 소스 파일에 대해서 JS의 strict mode 로 코드를 분석하고, “엄격하게 사용”을 해제 합니다

JS strict mode : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode

스크린샷, 2021-05-11 13-18-34

syntex 에러가 ts error 로 나온다

스크린샷, 2021-05-11 13-18-59

컴파일된 JS 파일에 “use strict” 가 추가 됨

🔑 10.결론

  • 항상 TS 사용할 때, strict mode 를 true 로 놓고 사용을 해야 합니다.

🔶 🔷 📌 🔑

Reference

Leave a comment