📕

1장 타입스크립트란?

1.1 자바스크립트의 한계

자바스크립트는 매우 유연한 언어이며 가장 큰 특징은 프로그램이 동작하는 시점에 실시간으로 타입이 결정되는 런타임 환경을 제공한다는 점입니다. 그리고 이 환경을 통해 코드를 작성하는 도중에 변수의 타입을 자유롭게 변경할 수 있습니다. 그러나 이 유연한 장점을 제공하는 런타임 환경에서 단점이 에러가 발생하게 될 가능성을 높게 만든다는 것입니다. 이는 개발단계에서 신속한 에러 발견과 수정을 어렵게 하고, 실제 서비스 환경에서 버그의 발생 가능성을 높입니다. 이로 인해 어떤 에러가 있는지 파악하기 어려운 위험한 상황이 초래될 수 있습니다.

1.2 타입스크립트란?

이러한 자바스크립트의 한계를 극복하기 위해 등장한 언어가 타입스크립트입니다. 타입스크립트는 자바스크립트를 기반으로 하는 언어로, 자바스크립트의 모든 기본 문법을 포함하며 추가적으로 타입 시스템을 도입하여 코드를 더 안전하게 관리할 수 있도록 지원하는 언어입니다.
또한 타입스크립트는 오픈 소스 프로젝트이기 때문에 깃허브에서 타입스크립트의 모든 소스 코드를 확인할 수 있으며, 모든 주요 브라우저 및 운영체제에서 지원되고 자바스크립트 코드로 변환되어 어떠한 환경에서도 실행할 수 있습니다.

1.2.1 타입 시스템

타입 시스템이란 타입 검사기가 프로그램에 타입을 할당하는 데 사용하는 규칙들의 집합입니다.
💡
규칙 (1) 자바스크립트 언어에서 사용할 수 있는 여러 가지 값들을 타입으로 구분 짓고 기준을 정의합니다. (2) 코드의 타입을 언제 검사할지를 결정하여, 프로그램이 실행되기 전에 정적으로 또는 프로그램 실행 도중에 동적으로 타입을 확인할 수 있습니다. (3) 코드를 분석하는 방법과 규칙을 정의하여 어떻게 타입을 검사할지를 정하여 코드에서 타입 에러를 찾아냅니다.
이런 언어의 타입 관련된 문법 체계 규칙들을 모아둔 것을 타입 시스템이라고 합니다. 그리고 타입 시스템은 동적 타입 시스템과 정적 타입 시스템 크게 두 가지로 나뉩니다.

1) 동적 타입 시스템 (Dynamic Type System)

동적 타입 시스템은 코드를 실행하고 나서 그때 그때 마다 유동적으로 변수의 타입을 결정하는 자유롭고 유연한 타입 시스템입니다. 이 타입 시스템을 통해 코드를 작성하는 도중에도 변수의 타입을 자유롭게 변경할 수 있으나 이러한 타입 시스템의 단점은 실행하기 전의 개발 단계에서 에러를 빠르게 발견하고 수정하는 것이 어렵다는 것입니다.
대표적인 언어로는 Python, JavaScript, Ruby 등이 있습니다.
let str = "hello" // string let num = 12345 // number let bool = true // boolean console.log(typeof str) // string console.log(typeof num) // number console.log(typeof bool) // boolean
위의 코드와 같이 우리가 직접 변수에 타입을 정해주지 않아도 코드가 실행되는 도중에 유동적으로 결정됩니다.
위의 코드와 같이 동적 타입 시스템의 대표적인 단점은 string 타입으로 선언된 myVar 변수에 12345 라는 값을 재할당하면서 number 타입으로 바뀌게 되었는데 코드는 실행 가능하며 코드를 실행한 후에 에러가 발생하게 된다는 것입니다.

2) 정적 타입 시스템 (Static Type System)

정적 타입 시스템은 코드 실행 이전에 모든 변수의 타입을 고정적으로 결정하는 엄격한 타입 시스템입니다. 이 타입 시스템은 코드를 실행하기 이전에 타입을 검사하여 에러를 빠르게 찾아낼 수 있습니다. 단점은 모든 변수에 일일이 타입을 결정해주어야 하기 때문에 코드의 양이 늘어나는 보일러 플레이트가 발생한다는 것입니다.
대표적인 언어로는 C, C++, Java, C# 등이 있습니다.
// TypeScript let str:string = "hello"; let num:number = 12345; let bool:boolean = true; let strNum = str * num; // Error let str.parseInt(); // Error
변수의 타입을 지정하는 데에는 변수명:type 형태로 지정 가능하며 이를 어노테이션(Annotation) 이라고 부릅니다. 어노테이션을 통해 변수의 타입을 지정하면 다시 해당 변수의 타입을 변경할 수 없습니다. 그리고 위의 코드에서 str * numstr.parseInt() 에 타입 체크를 한 결과 타입이 서로 맞지 않아 결과값을 낼 수 없거나 해당 타입에 대한 메서드가 일치하지 않아 프로그램 실행 전에 에러를 찾아낼 수 있는 특징이 있습니다.

3) 점진적 타입 시스템 (Gradual Type System)

점진적 타입 시스템은 정적 타입 시스템의 보일러 플레이트 문제를 해결하기 위해 도입된 것으로, 모든 변수에 일일이 타입을 지정해 주는 번거로움을 없애고 코드를 실행하기 전에 정적으로 변수의 타입을 결정함으로써 유연성을 제공합니다. 또한, 동적 타입 시스템의 단점인 예상할 수 없는 타입 에러를 사전에 검사할 수 없는 문제를 보완하기 위해 코드를 실행하면서 유동적으로 변수의 타입을 결정하므로, 타입 안정성을 확보합니다. 이러한 특징은 타입스크립트에서만 볼 수 있는 독특한 타입 시스템입니다.
// TypeScript let myVar = "hello" myVar = 12345 // Error myVar.parseInt(); // Error
위의 코드는 점진적 타입 시스템이 적용된 예시입니다. myVar 변수를 일일이 어노테이션을 통해 타입을 지정해 주지 않아도 동적으로 타입이 결정되며 해당 변수의 타입은 자바스크립트와는 다르게 재할당을 통해 다시 타입을 변경할 수 없습니다. 그리고 동적으로 타입이 결정된 변수에 일치하지 않는 메서드를 넣은 코드를 실행시키면 프로그램이 실행되기 전에 타입 검사를 하여 에러를 찾아낼 수 있습니다.
 

1.3 타입 추론

타입스크립트는 모든 상황의 타입을 알아서 잘 추론 해주지는 않습니다. 어느 상황에서 동적으로 타입이 추론되고 정적으로 타입을 지정해 주어야 되는지 알아보겠습니다.

1.3.1 동적으로 추론 가능한 타입

1) 변수 선언

let num = 10; // number let str = "hello"; // string let bool = true; // boolean

2) 변수 선언 및 미할당

let myVar; // any myVar = "hello" // string myVar = 10; // number myVar = true; // boolean
변수를 선언하고 값을 할당해 주지 않으면 암묵적으로 any 타입이 지정됩니다. 그리고 변수에 새로운 값을 할당해 줄 때마다 타입이 바뀌게 됩니다. 이를 any 타입의 진화라고 부르기도 합니다.

3) 객체 선언 및 구조분해할당

let obj = { id : 1, // number userName : "조병민", // string introduce : "반갑습니다.", // string adult : true, // boolean } let { id, userName, introduce, adult } = obj; // number, string, string, boolean

1.3.2 동적으로 추론 불가능한 타입

1) 함수

function userAdd(userinfo) {} // Error
함수의 매개변수는 동적으로 타입을 추론해 주지 않기 때문에 어노테이션을 통해 정적으로 타입을 지정해 주지 않으면 에러가 발생합니다.

2) 배열

let userList = []; userList.push("조병민"); // Error
위의 경우에 배열에 유저의 이름을 push를 통해 넣고 있습니다. 하지만 배열에는 어떤 타입의 값이 들어와도 되는지 타입스크립트는 추론해내지 못합니다. 따라서 미리 배열을 선언할 때 어떤 타입의 값이 들어올 수 있는지 어노테이션을 통해 정적으로 지정해주어야 합니다.
 

1.4 타입스크립트 환경 설정

타입스크립트를 사용하려면 먼저 Node.js를 설치해야 합니다. Node.js 를 설치하면 npm이 함께 설치되고, npm을 통해서 타입스크립트를 설치할 수 있습니다.
npm이란? npm은 Node Package Manager의 약자로, Node.js에서 사용되는 패키지 모듈을 관리하는 데 사용되는 도구입니다. npm을 사용하면 이미 만들어진 모듈을 재사용할 수 있고, 버전 관리도 쉽게 할 수 있습니다.

1.4.1 Node.js 설치하기

Node.js는 공식 웹사이트에서 직접 다운로드 받아 설치할 수도 있고, 맥OS 사용자의 경우 Homebrew라는 맥OS 전용 패키지 매니저를 이용하여 설치할 수도 있습니다.

1) Node.js 홈페이지에서 Node.js 설치하기 (맥OS 설명)

아래 Node.js 홈페이지에 들어갑니다. https://nodejs.org/en
Node.js 사이트Node.js 사이트
Node.js 사이트
홈페이지에 들어가게 되면, LTS 버전과 Current 버전이 있습니다. LTS 버전은 장기 지원 버전으로, 좀 더 안정적으로 Node.js를 사용할 수 있다는 장점이 있습니다. Current 버전은 새로운 기능을 빠르게 사용할 수 있다는 장점이 있지만, 안정화되지 않았을 수 있어 사용에 주의해야 합니다.
여기서는 LTS 버전을 다운로드하겠습니다. 다운로드 버튼을 누르면 아래 파일이 다운로드됩니다.
Node.js 파일Node.js 파일
Node.js 파일
파일을 클릭하면 아래와 같은 창이 뜹니다. Node.js와 npm이 같이 설치되는 것을 확인할 수 있습니다.
Node.js 설치Node.js 설치
Node.js 설치
Node.js 설치Node.js 설치
Node.js 설치

2) 맥OS 용 패키지 관리자 Homebrew로 Node.js 설치하기

MacOS 사용자는 Homebrew라는 패키지 관리자를 이용해서 Node.js를 설치하고 관리할 수 있습니다. 이때, Homebrew로 직접 Node.js를 설치할 수도 있고, Homebrew로 NVM을 설치한 다음, Node.js를 설치하고 관리할 수 있습니다.
여기서는 위 2가지 방법을 모두 설명하겠습니다.
먼저 Homebrew를 설치합니다.
Homebrew란? Homebrew 홈페이지 : https://brew.sh/ Homebrew는 맥OS 운영 체제를 위한 무료 오픈소스 소프트웨어 패키지 관리 시스템입니다. 많은 맥OS 사용자들이 소프트웨어 패키지를 관리하기 위해 Homebrew를 사용합니다.
 
Homebrew 사이트Homebrew 사이트
Homebrew 사이트
 
터미널을 열고 Homebrew가 설치되어 있는지 확인합니다.
brew --version
만약, Homebrew가 설치되어 있다면 아래처럼 버전 정보가 출력됩니다.
Homebrew 4.2.6 Homebrew/homebrew-core (git revision 67af0873b8e; last commit 2024-02-01) Homebrew/homebrew-cask (git revision 258facca1e; last commit 2024-02-01)
Homebrew가 설치되어 있지 않다면, 아래와 같은 메시지가 출력됩니다.
zsh: command not found: brew
Homebrew가 설치되어 있지 않다면, 터미널에 아래 명령어를 입력하여 Homebrew를 설치합니다. 이 명령어는 Homebrew 홈페이지에도 있습니다.
/bin/bash -c "$(curl -fsSL <https://raw.githubusercontent.com/Homebrew/install/master/install.sh>)"
 
(1) Homebrew로 Node.js 설치하기
Homebrew로 Node.js 를 설치하려면 터미널을 열고, 아래 명령어를 입력하기만 하면됩니다.
brew install node
이 방법은 간단하지만 시스템 전역에 Node.js가 설치되기 때문에, 다양한 버전의 Node.js를 필요로 하는 개발 환경에서는 불편할 수 있습니다.
 
(2) Homebrew로 NVM 설치하고, Node.js 설치및 관리하기
💡
NVM 이란? NVM은 Node Version Manager의 약자로 이름 그대로 다양한 버전의 Node.js를 설치하고 관리하는 기능을 제공합니다.
터미널을 열고 아래 명렁어로 NVM을 설치합니다.
brew install nvm
NVM 설치 후, NVM을 사용하기 위해 .nvm 디렉터리를 생성합니다. 이 디렉터리는 NVM이 설치한 Node.js 버전들과 관련 데이터를 관리하는 데 사용됩니다.
mkdir ~/.nvm
이제 쉘 환경 설정 파일을 열고 코드를 추가해야 합니다. 이때 NVM을 제대로 로드하기 위해서는, 현재 사용하고 있는 쉘에 맞는 환경 설정 파일을 수정해야 합니다.
zsh 를 사용할 경우
open -a TextEdit ~/.zshrc
bash를 사용할 경우
open -a TextEdit ~/.bash_profile
쉘 환경 설정 파일을 열고 맨 아래부분에 아래 코드를 추가합니다.
export NVM_DIR="$HOME/.nvm" [ -s "/usr/local/opt/nvm/nvm.sh" ] && . "/usr/local/opt/nvm/nvm.sh" # This loads nvm [ -s "/usr/local/opt/nvm/etc/bash_completion.d/nvm" ] && . "/usr/local/opt/nvm/etc/bash_completion.d/nvm" # This loads nvm bash_completion
변경사항을 수정했다면, 변경사항을 적용하기 위해 아래 명령어를 입력하고 실행합니다.
source ~/.zshrc # zsh를 사용하는 경우 source ~/.bash_profile # bash를 사용하는 경우
nvm —version 명령어로 NVM이 설치되었는지 확인할 수 있습니다.
nvm 설치 확인nvm 설치 확인
nvm 설치 확인
💡
그래도 command not found: nvm 가 발생한다면? Homebrew를 통해 설치된 NVM의 경로가 /usr/local/opt/nvm/nvm.sh가 맞는지 확인해야 합니다. brew --prefix nvm 명령어로 NVM이 설치된 경로를 확인할 수 있습니다. 이 경로가 아니라 /opt/homebrew/opt/nvm 라면, 쉘 환경 설정 파일에 추가한 코드의 내용을 아래와 같이 수정해줍니다.
 
export NVM_DIR="$HOME/.nvm" [ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && . "/opt/homebrew/opt/nvm/nvm.sh" # This loads nvm [ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && . "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" # This loads nvm bash_completion
 
이제 NVM으로 Node.js를 설치해 보겠습니다.
NVM을 통해 설치 가능한 Node.js 버전을 확인할 수 있습니다. 아래 명령어는 설치 가능한 모든 Node.js 버전을 보여줍니다.
nvm list-remote
NVM으로 Node.js의 LTS 버전을 설치할 수 있습니다.
nvm install --lts
특정 버전의 Node.js를 설치하고 싶다면, 해당 버전을 명시하면 됩니다.
nvm install 20.11.0

1.4.2 타입스크립트 설치하기

Node.js를 설치했다면 npm을 이용해 타입스크립트를 설치할 수 있습니다.
우선 Visual Studio Code를 열고 타입스크립트를 설치할 폴더를 엽니다. 그리고 Visual Studio Code 터미널 창에 아래 명령어 작성 후 실행시키면, 타입스크립트가 설치됩니다.
npm install typescript
타입스크립트가 제대로 설치되었는지 확인하려면 아래 명령어를 입력하고 실행시키면 됩니다.
npm ls typescript
타입스크립트 버전타입스크립트 버전
타입스크립트 버전

1.4.3 타입스크립트 사용해보기

이제 타입스크립트 파일을 생성하고, 실행까지 시켜보겠습니다. 타입스크립트를 설치한 폴더 안에 타입스크립트 파일을 만듭니다.
hello.ts 파일hello.ts 파일
hello.ts 파일
hello.ts 파일에 아래 코드를 작성합니다.
function greet(name: string): void { console.log(`hello, ${name}`); } greet('TypeScript');
터미널을 열고 아래 명령어를 입력하고 실행하면 hello.js 파일이 생성됩니다.
tsc hello.ts
이 과정을 타입스크립트 파일을 자바스크립트 파일로 컴파일한다고 합니다. 타입스크립트 파일을 자바스크립트 파일로 컴파일하는 이유는, 타입스크립트 코드는 브라우저에서 실행할 수 없기 때문입니다. 그래서 호환 가능한 자바스크립트 파일로 컴파일해줘야 합니다.
그리고 다시 터미널에 아래 명령어로 hello.js 파일을 실행하면 출력 결과를 확인할 수 있습니다.
node hello.js
타입스크립트 실행타입스크립트 실행
타입스크립트 실행

1.4.4 타입스크립트 컴파일러 환경설정 tsconfig.json 세팅

tsc 명령어로 타입스크립트 코드를 자바스크립트 코드로 컴파일할 수 있다고 했습니다.
이때, 타입스크립트 컴파일러가 컴파일을 진행합니다. 이 컴파일러의 컴파일 옵션을 지정할 수 있는데 그 파일의 이름이 tsconfig.json입니다. tsconfig.json 없이 tsc 명령을 실행하면, 타입스크립트 컴파일러는 기본 설정만을 사용하여 컴파일합니다. 이렇게 되면 프로젝트의 특정 요구에 맞는 세밀한 설정을 할 수 없습니다. 따라서 tsconfig.json을 통해 설정할 수 있는 컴파일 옵션에는 어떤 것들이 있는지 알아둘 필요가 있습니다.

1) tsconfig.json 생성

Visual Studio Code 터미널 창에서 tsc --init 명령어로 tsconfig.json 파일을 생성할 수 있습니다. 생성된 tsconfig.json 파일을 보면 타입스크립트 컴파일러 설정을 위한 기본 구조가 생성됩니다. 또한, 생성된 파일에는 각 옵션에 대한 설명이 주석으로 포함되어 있어, 옵션의 의미와 사용법을 쉽게 이해할 수 있게 되어있습니다.
tsconfig.jsontsconfig.json
처음 파일을 생성하면 compilerOptions 속성만 있습니다. 이렇게 파일 최상위에 위치하고 있는 속성들을 tsconfig 전역 속성이라고 합니다. 전역 속성에는 다양한 종류가 있지만 여기서는 컴파일러 옵션을 정할 수 있는 compilerOptions 속성만 다루겠습니다.

2) compilerOptions 속성

타입스크립트 컴파일러는 많은 옵션을 제공하고 있습니다. 모든 옵션을 다 알아볼 수는 없으므로 일부 속성들에 대해서만 알아보겠습니다.
더 많은 컴파일러 옵션과 자세한 설정값에 대한 내용은 아래 페이지에서 확인할 수 있습니다. TSConfig Reference : https://www.typescriptlang.org/ko/tsconfig#compilerOptions
(1) target
target 옵션은 컴파일된 자바스크립트 코드의 ECMAScript 버전을 지정합니다. 기본값은 es3입니다. 그 밖에도 es6, es6/es2015, es2022 등 다양한 버전을 선택할 수 있습니다.
{ "compilerOptions": { "target": "es6", } }
(2) module
module 옵션은 컴파일된 자바스크립트 코드가 어떤 모듈 시스템을 사용할지 지정합니다. 만약 target 옵션이 es5나 es3로 설정되어 있다면, module의 기본값은 CommonJS로 설정됩니다. target 옵션이 es6(또는 es2015) 이상으로 설정되어 있다면, module의 기본값은 es6(또는 es2015) 모듈 시스템으로 설정됩니다. module 설정을 선택할 때는 생성할 자바스크립트 코드가 어떤 환경에서 실행될 것인지를 고려해서 선택해야 합니다.
CommonJS는 Node.js 환경에서 주로 사용하는 모듈 시스템으로, require, module.exports 문법으로 모듈을 가져오고 내보낼 수 있습니다.
es6(es2015) 즉, ES Module은 es6에 도입된 모듈 시스템으로, import, export 문법으로 모듈을 가져오고 내보낼 수 있습니다. module 속성값으로 ECMAScript의 차기 버전이란 의미의 esnext로 설정할 수도 있습니다.
{ "compilerOptions": { "target": "es6", "module": "es6", // 또는 esnext } }
(3) rootDir, outDir
rootDir 옵션은 타입스크립트 컴파일러에게 어디에서 타입스크립트 파일을 찾아야 하는지 알려줍니다. ./src로 설정되어 있다면 프로젝트의 루트 디렉터리에 있는 src 폴더 내의 타입스크립트 파일들을 대상으로 컴파일합니다.
outDir 옵션은 컴파일된 자바스크립트 파일들이 어디에 있어야 하는지 지정합니다. 이 값을 지정해주지 않으면, 컴파일된 파일들은 기본적으로 타입스크립트 파일과 같은 경로에 자바스크립트 파일을 생성합니다.
어떻게 동작하는지 확인하기 위해, 우선 src 폴더와 build 폴더를 생성합니다. 그리고 src 폴더 안에 hello.ts 파일을 생성하고 내용을 작성합니다.
hello.ts 파일hello.ts 파일
hello.ts 파일
hello.ts
function greet(name: string): void { console.log(`hello, ${name}`); } greet("TypeScript");
tsconfig.json를 아래처럼 수정합니다.
{ "compilerOptions": { "target" : "es6", "module": "es6", "rootDir": "./src", "outDir": "./build/js", } }
 
이제 터미널에서 프로젝트 루트 디렉터리 경로로 이동한 다음, tsc -w 명령어를 실행합니다.
타입스크립트 파일 컴파일타입스크립트 파일 컴파일
타입스크립트 파일 컴파일
hello.js 파일hello.js 파일
hello.js 파일
tsconfig.json 파일에서 설정한 경로대로 컴파일된 파일이 생성되는 것을 볼 수 있습니다.
 
(4) strict
strict 옵션은 타입스크립트의 각종 엄격한 타입 체킹 모드를 활성화하는 옵션입니다.
strict 옵션을 true로 설정하면 아래 strict mode family 옵션들을 전부 활성화하는 것과 같습니다. 여기서는 각 옵션이 어떻게 동작하는지 설명하기 위해서 strict를 false로 설정하고 각 옵션만 활성화하는 방식으로 알아보겠습니다. 먼저 src 폴더 안에 test.ts 파일을 생성합니다. 그리고 tsc -w 명령어로 watch 모드를 켜둔 상태로 진행합니다.
 
noImplicitAny
타입을 명시적으로 지정하지 않은 경우 any 타입으로 추론하지 않고, 오류를 발생시킵니다.
tsconfig.json
"compilerOptions": { ..., "strict": false, "noImplicitAny": false, }
test.ts 파일에 아래 코드를 작성합니다. 이때 a, b는 any 타입으로 추론되고 에러가 발생하지 않습니다.
function add(a, b) { return a + b; }
"compilerOptions": { ..., "strict": false, "noImplicitAny": true, }
true로 바꾸고 test.ts 파일을 확인하면, 에러가 발생합니다.
에러 메시지에러 메시지
에러 메시지
strictNullchecks
null과 undefined 값을 엄격하게 처리하도록 설정합니다. 이 옵션을 비활성화하면 타입스크립트는 null과 undefined를 모든 타입에 할당할 수 있도록 허용합니다. 하지만 이 옵션을 활성화하면, null과 undefined는 오직 any, unknown 또는 null은 null 타입에, undefined는 undefined 타입에만 할당할 수 있게 됩니다.
"compilerOptions": { ..., "strict": false, "strictNullchecks": false, }
let strVar: string; let anyVar: any; let unknownVar: unknown; let undefinedVar: undefined; let nullVar: null; strVar = null; strVar = undefined; anyVar = null; anyVar = undefined; unknownVar = null; unknownVar = undefined; undefinedVar = null; nullVar = undefined;
 
"compilerOptions": { ..., "strict": false, "strictNullchecks": true, }
let strVar: string; let anyVar: any; let unknownVar: unknown; let undefinedVar: undefined; let nullVar: null; anyVar = null; anyVar = undefined; unknownVar = null; unknownVar = undefined; undefinedVar = undefined; nullVar = null; undefinedVar = null; // Error nullVar = undefined; // Error strVar = null; // Error strVar = undefined; // Error
에러 메시지에러 메시지
에러 메시지
strictFunctionTypes
이 옵션은 타입스크립트에서 함수 매개변수에 대한 할당 가능성을 엄격하게 검사할 수 있게 설정합니다.
"compilerOptions": { ..., "strict": false, "strictFunctionTypes": true, }
type A = (x: string | number) => void; type B = (x: string) => void; const AFunction: A = (x: string | number): void => {}; const BFunction: B = (x: string): void => {}; let AB: A = BFunction; // Error let BA: B = AFunction;
에러 메시지에러 메시지
에러 메시지
strictFunctionTypes가 true일 때 함수 매개변수 타입에 반공변적 타입 체크를 적용하는데 이는, 하위 타입에서 상위 타입으로의 할당은 허용하지만, 상위 타입에서 하위 타입으로의 할당은 허용하지 않는다는 의미입니다. 이로 인해 AB의 할당은 상위 타입에서 하위 타입으로의 할당이므로 오류가 발생합니다.
strictFunctionTypes가 false일 때, 타입스크립트는 함수 매개변수 타입에 대해 이변성을 허용하는데 이는, 상위 타입에서 하위 타입으로의 할당이 가능해짐을 의미합니다. 이로 인해 AB의 할당이 허용되면서, 에러가 발생하지 않습니다.
 
strictBindCallApply
타입스크립트에서 bind, call, apply 메서드를 사용할 때 더 엄격한 검사를 설정하는 옵션입니다. 이 옵션이 비활성화 되어 있다면 bind, call, apply에 전달된 인수에 대해 덜 엄격한 타입 검사를 수행합니다.
"compilerOptions": { ..., "strict": false, "strictBindCallApply": false, }
function multiply(x: number, y: number) { console.log(x * y); } const boundMultiply = multiply.bind(null, "A", 25); boundMultiply();
bind에 전달된 인수에 대해 덜 엄격한 타입 검사를 하기 때문에 위 코드는 타입 에러가 발생하지 않습니다.
"compilerOptions": { ..., "strict": false, "strictBindCallApply": true, }
옵션을 활성화하면 에러가 발생합니다.
notion imagenotion image
 
strictPropertyInitialization
이 옵션이 활성화되어 있을 경우, 타입스크립트 클래스의 모든 멤버 변수는 생성자 내에서 반드시 초기화되어야 합니다.
타입스크립트 클래스에서는 클래스의 프로퍼티를 사용하려면, 먼저 클래스 본문에서 해당 프로퍼티를 선언해야 합니다. 그 후에 생성자 또는 메서드에서 해당 프로퍼티를 사용할 수 있습니다.
class User { id: number; name: string; constructor(id: number, name: string) { this.id = id; this.name = name; } }
만약 클래스 본문에서 프로퍼티를 선언하지 않으면 에러가 발생합니다.
class User { id: number; name: string; constructor(id: number, name: string, age: number) { this.id = id; this.name = name; this.age = age; // Error } }
에러 메시지에러 메시지
에러 메시지
타입스크립트 클래스에서 프로퍼티를 사용하려면 클래스 본문에 프로퍼티를 먼저 선언해야 하기 때문에 이 옵션을 활성화하면 클래스 본문에 선언한 프로퍼티가 생성자에서 초기화되지 않는 실수를 잡을 수 있습니다.
"compilerOptions": { ..., "strict": false, "strictNullChecks": true, "strictPropertyInitialization": true, }
아래처럼 멤버변수가 생성자 함수 내부에서 초기화되지 않은 경우 에러가 발생합니다. strictPropertyInitialization 옵션이 비활성화 되어 있으면 에러가 발생하지 않습니다.
class User { id: number; // Error name: string; constructor(id: number, name: string) { this.name = name; } }
에러 메시지에러 메시지
에러 메시지
타입스크립트 접근 제어자(public, private, protected)를 붙이면 선언과 초기화를 한 번에 할 수 있습니다.
class User { constructor(public id: number, public name: string) { // 타입스크립트 코드에서 // this.id = id, this.name = name 코드는 필요 없어집니다. } }
 
그리고 이 옵션이 제대로 작동하기 위해서는 strictNullChecks 옵션은 true로 설정해야 합니다. strictNullChecks옵션이 활성화되어 있지 않다면 에러가 발생합니다.
"compilerOptions": { ... "strict": false, "strictNullChecks": false, "strictPropertyInitialization": true, }
class User { constructor(public id: number, public name: string) {} }
에러 메시지에러 메시지
에러 메시지
noImplicitThis
이 옵션은 this의 타입을 명시적으로 지정하도록 요구하는 옵션입니다. 이 옵션을 활성화한 상태에서 아래처럼 코드를 작성하면 sayHello 메서드가 반환하는 함수에서 this는 any 타입을 가지게 됩니다.
"compilerOptions": { ... "strict": false, "noImplicitThis": true, } test.ts
class Person { constructor(public name: string) { this.name = name; } sayHello() { return function() { console.log(`hello ${this.name}`); // Error } } } const person = new Person("John"); const sayPerson = person.sayHello(); sayPerson.call(person);
noImplicitThis를 활성화시키면 컴파일 에러를 발생시킬 수 있습니다.
에러 메시지에러 메시지
에러 메시지
이 컴파일 에러를 해결하려면 this의 타입을 명시적으로 선언하면 됩니다.
class Person { constructor(public name: string) { this.name = name; } sayHello() { return function (this: Person) { console.log(`hello ${this.name}`); }; } } const person = new Person("John"); const sayPerson = person.sayHello(); sayPerson.call(person);
이 코드에서 this 매개변수는 가짜 매개변수로 실제로 함수에 전달되는 것이 아니라, this의 타입을 명시적으로 지정하는 역할을 합니다.
또 화살표 함수를 사용할 수도 있습니다. 화살표 함수를 사용하면 this의 타이핑과 call 메서드의 사용이 필요 없어집니다. 일반 함수에서 this는 호출 시점에서 결정되는 반면, 화살표 함수에서 this는 선언 시점에 결정됩니다. 그래서 화살표 함수는 자신을 감싸는 영역의 this를 물려받습니다. 아래 코드에서 sayHello 메서드의 this가 가리키는 게 Person입니다. 그래서 sayHello가 반환하는 화살표 함수의 this도 Person이 됩니다.
class Person { constructor(public name: string) {} sayHello() { return () => { console.log(`hello ${this.name}`); }; } } const person = new Person("John"); const sayPerson = person.sayHello(); sayPerson();
 
alwaysStrict
이 옵션은 컴파일된 자바스크립트 파일이 엄격 모드(use strict)를 사용하도록 합니다. 그래서 타입스크립트 코드를 컴파일한 후의 자바스크립트 코드에 영향을 미칩니다. 즉, alwaysStrict 옵션은 타입스크립트 코드의 타입 오류를 잡아내는 것과는 별개로, 컴파일된 자바스크립트 코드가 실행될 때 발생할 수 있는 일반적인 자바스크립트 오류를 방지하는 데 도움을 줍니다.