ES6는 이크마에서 2015년에 채택한 자바스크립트 표준이다. ES6 이후로 자바스크립트에는 많은 변화가 있었다. 새로 추가된 기능이 많은데 같이 알아봅시다 ! 😃

변수를 정의하는 새로운 방법 const, let

es5까지의 자바스크립트에서는 var를 이용해서 변수를 정의했고 그게 유일한 방법이었다면 ES6에서는 const / let을 이용하는 새로운 변수 정의 방법이 생겼다. 새로운 방법이 나온 이유는 기존 방식으로는 해결되지 않는 문제가 있었기 때문이다. 자바스크르립트가 저급한 언어라고 무시당하던(?) ES6 이전 시절, var가 그 비난에 한몫하지 않았을까 싶다.

var가 가진 문제를 알아보자

1. var = 함수 스코프

  •  var의 첫 번째 문제는 정의된 변수가 함수 스코프를 가진다는 것이다. 스코프란 변수가 사용될 수 있는 영역을 말한다. 스코프는 변수가 정의된 위치에 의해 결정된다. var로 정의된 변수는 함수를 벗어난 영역에서 사용하면 에러가 발생한다.
function example() {
 var i = 1;
 }
 console.log(i);

var 변수를 함수가 아닌 프로그램의 가장 바깥에 정의하면 전역 변수가 되는데, 이는 프로그램 전체를 감싸는 하나의 함수가 있다고 생각하면 이해하기 쉽다. 특이한 점은 함수 안에서 var 키워드를 사용하지 않고 변수에 값을 할당하면 그 변수는 전역 변수가 된다는 점이다. var는 함수 스코프이기 때문에 for 반복문에서 정의된 변수가 반복문이 끝난 이후에도 계속 남는 문제점이 있다. for 문 뿐만 아니라 while문, switch문, if문 등 함수 내부에서 작성되는 모든 코드는 같은 문제를 안고 있다. var 변수의 스코프를 제한하기 위해 즉시 실행 함수를 사용하기도 한다. 

 

즉시 실행 함수란 ?

함수를 정의하는 시점에 바로 실행되고 사라진다. var 변수는 함수 스코프이므로 즉시 실행 함수로 묶으면 변수의 스코프를 제한할 수 있다. 그러나 즉시 실행 함수는 작성하기 번거롭고 가독성도 떨어진다

 

2. 호이스팅

var로 정의된 변수는 그 변수가 속한 스코프의 최상단으로 끌어올려진다. 이를 호이스팅이라고 부른다. 호이스팅은 직관적이지 않으며, 보통의 프로그래밍 언어에서는 찾아보기 힘든 성질이다.

 

3. 재정의

var myvar = 1;
var myvar = 2;

var를 이용하면 한 번 정의된 변수를 재정의할 수 있다. 변수를 정의한다는 것은 이전에 없던 변수를 생성한다는 의미로 통용된다. 따라서 앞의 코드가 에러 없이 사용될 수 있다는 것은 직관적이지 않으며 버그로 이어질 수 있다.

 

 


 

위에 같은 var의 문제를 해결해주는 const, let !

const, let은 블록 스코프다. var는 함수 스코프였지만 const,let은 블록 스코프라 부른다. 블록 스코프에서 if 문의 블록 안에서 정의된 변수는 if 문을 벗어나면 참조할 수 없다. if 문에서 생성된 변수를 블록 바깥에서 사용하려고 하면 에러가 발생한다. 이러한 상황에서 에러가 발생하는 것이 직관적이며 이해하기도 쉽다. 

 

1. const,let에서의 호이스팅

const, let으로 정의된 변수도 호이스팅 된다. 하지만 const, let으로 변수를 정의하기 전에 그 벼수를 사용하려고 하면 참조 에러가 발생한다.

console.log(foo); //참조에러
const foo = 1; 

똑같은 경우 var는 에러가 발생하지 않는다. 따라서 const, let으로 정의된 변수는 호이스팅이 되지 않는다고 생각하기 쉽다. 하지만 const, let으로 정의된 변수도 호이스팅되나. 다만 변수가 정의된 위치와 호이스팅된 위치 사이에서 변수를 사용하려 하면 에러가 발생한다. 이 구간을 임시적 사각지대라고 부른다.

 

2. const는 변수를 재할당 불가능하게 만든다.

const로 정의된 변수는 재할당이 불가능하다. 반대로 let, var로 정의된 변수는 재할당 할 수 있다. 재할당 불가능한 변수는 프로그램의 복잡도를 상당히 낮춰주기 때문에 되도록이면 재할당 불가능한 변수를 사용하는 게 좋다. 이미 존재하는 속성값을 수정하거나 새로운 속성값을 추가하는 것 모두 가능하다. 객체의 내부 속성값도 수정 불가능하게 만들고 싶다면 immer, immutable.js 등의 외부 패키지를 활용하는게 좋다. 이러한 외부 패키지는 객체를 수정하려 할 때 기존 객체는 변경하지 않고 새로운 객체를 생성한다. 새로운 객체를 생성하는 편의 기능은 필요 없고 단지 수정만 할 수 있도록 차단하고 싶다면, 이런 자바스크립트 내장 함수를 이용하면 된다.

  • Object.preventExtenstions
  • Object.seal
  • Object.freeze

그리고 const로 정의 했다면 객체를 참조하는 변수 자체를 변경하는 것은 불가능 !

 

 

 

ESLint

- 자바스크립트 문법 및 코드 스타일을 검사해 주는 도구이다.

에디터에 뜬 경고처럼 초록색 줄이 그어진 코드는 고치기 싫다면 무시해도 되지만 빨간줄은 반드시 고쳐야 한다. 이런 오류는 고치지 않으면 페이지가 브라우저에 나타나지 않는 치명적인 오류이므로 꼭 고쳐줘야 한다.

 

Reactjs Code Snippets

- (제작자가 charalampos karypidis)인 것으로 설치하기 

리액트 컴포넌트 및 라이프사이클 함수를 작성할 때 단축 단어를 사용하여 간편하게 코드를 자동으로 생성해 낼 수 있는 코드 스니펫 모음이다.

 

Prettier-Code formatter

- 코드 스타일을 자동으로 정리해 주는 도구. JSX를 작성 시 코드의 가독성을 위해 들여쓰기를 사용한다. 들여쓰기가 제대로 되어 있지 않은 코드는 가독성이 매우 떨어지기 때문이다. 혹여나 다른 포맷도구 (Beautify) 설치하면 충돌 발생할 수 있으니 조심하기. Prettier를 사용하여 자동 코드 정리를 하면 코드가 제대로 정렬되고, 세미콜론이 빠진 곳은 자동 추가되고 기존에 사용하던 작은 따옴표는 모두 큰 따옴표로 바뀌었을 것이다. 이런 부분은 협업하는 과정에서 정하는 규칙이다.

 

그리고 Prettier의 장점은 이러한 스타일을 쉽게 커스터마이징 해준다는 점도 있다. 현재 열려있는 프로젝트의 루트 디렉토리에서 .prettierrc라는 파일을 생성 한 후 이런 내용을 적어보자.

{
  "printWidth": 120, //글자수
  "tabWidth": 2, //탭 칸
  "singleQuote": true,//''
  "trailingComma": "all",//, 찍어주기
  "semi": true//;세미콜론
  "useTabs" : false,//공백 대신 탭으로
}

이것은 파일에서 들여쓰기 할 때 탭 대신 공백을 두 칸 사용. 그리고 큰따옴표 대신 작은 따옴표. 세미콜론은 언제나 붙이도록 설정했다.

 

VS Code 언어 한국어로 설정하기

Korean Language Pack for Visual Studio Code를 설치한다.

 

Reactjs Code Snippet

VS Code에서 위 확장 프로그램을 설치했다면 컴포넌트 코드를 간편하고 빠르게 생성할 수 있다.

웹팩은 여러개 파일을 하나의 파일로 만들어 주는 번들러(bundler)다. 하나의 시작점으로부터 의존적인 모듈을 전부 찾아내서 하나의 결과물을 만들어 낸다. app.js 부터 시작해 math.js 파일을 찾은 뒤 하나의 파일로 만드는 방식이다.  번들 작업을 하는 webpack 패키지와 웹팩 터미널 도구인 webpack-cli를 설치한다.

$npm install -D webpack webpack-cli

설치 완료하면 node_modules/.bin 폴더에 실행 가능한 명령어가 몇 개 생긴다. webpack과 webpack-cli가 있는데 둘 중 하나를 실행하면 된다. 여기서 사용된 -D는 개발용 dependencies다.

 

https://webpack.js.org/

 

웹팩을 실행 할 때에는 필수적인 옵션이 있다.

1. --mode => development, production, none이 있는데 개발환경이냐 운영환경이냐에 따라서 development, production을 설정한다.

  • development : 개발용 정보를 추가할 때
  • production : 운영에 배포하기 위한 것

 

js가 시작 (entry) 그리고 js, css, jpg, png로 아웃풋 해주는 그림이다.

2. 모듈의 시작점 : entry 라고 한다.

3. entry를 통해 모든걸 하나로 합치고 경로를 저장하는 것은 output 이라고 한다.

$node_modules/.bin/webpack --mode development --entry ./src/app.js --output dist/main.js

webpack의 mode는 개발용이고 entry(시작점)은 ./src/app.js 이며 이 모든걸 하나로 합치고 경로를 저장하는 최종 아웃풋은 dist/main.js에 담으라는 뜻이다. 웹팩은 이처럼 여러개의 모듈을 하나의 파일로 만들어주는 역할을 한다.

 


 

웹팩 설정 파일

웹팩 설정 파일명 [webpack.config.js] 또는 [webpackfile.js] 로 지정한다.

{
  "name": "fn_dev_env",
  "version": "1.0.0",
  "description": "<br>",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "author": "leehyunju",
  "license": "ISC",
  "dependencies": {
    "react": "^17.0.1"
  },
  "devDependencies": {
    "webpack": "^4.46.0",
    "webpack-cli": "^4.5.0"
  }
}

 

여기서 script안에 있는 build를 "webpack"으로 하면 현재 프로젝트에 있는 노드 모듈을 뒤져서 웹팩 명령어를 찾는다. 그럼 웹팩은 기본 webpack.config.js 파일을 읽어서 번들링을 해줄 것이다.

 

패키지설치

가장 간단한 방법은 CDN으로 제공하는 라이브러리를 직접 가져오는 방식이다. 리액트의 주소를 html에서 로딩해준다. 하지만 주의해줘야 될 것이 아무리 우리 어플리케이션 서버가 정상이더라도 필수 라이브러리를 가져오지 못한다면 웹 어플리케이션은 정상적으로 동작할 수 없다. 그런 장애와 무관하게 우리가 직접 다운로드를 하는 방법이 있다.

 

명령어

npm install [설치할 라이브러리]

 

예를 들어 npm install react 했을 경우, 밑에처럼 package.json 파일에 dependencies 안에 react가 설치 된 것을 확인 할 수 있다.

 


 

IIFE (즉시 실행 함수 표현)

정의되자마자 즉시 실행되는 자바스크립트 함수를 말한다.

var math = math || {};

(function () {
 function sum(a,b) {
 retrun a + b;
 } 
  math.sum = sum;
 })();

1. 첫 번째는 괄호((), Grouping Operator)로 둘러싸인 익명함수(Anonymous Function)이다. 이는 전역 스코프에 불필요한 변수를 추가해서 오염시키는 것을 방지할 수 있을 뿐 아니라 IIFE 내부안으로 다른 변수들이 접근하는 것을 막을 수 있는 방법이다.

2. 두 번째 부분은 즉시 실행 함수를 생성하는 괄호()이다. 이를 통해 자바스크립트 엔진은 함수를 즉시 해석해서 실행한다.

 

(function () {
    var aName = "Barry";
})();

aName 

IIFE 내부에서 정의된 변수는 외부 범위에서 접근이 불가능하다.

// throws "Uncaught ReferenceError: aName is not defined"

 

다양한 모듈 스펙 알아보기

자바스크립트 모듈을 구현하는 대표적인 명세가 AMD와 CommonJS다. CommonJS는 자바스크립트로 사용하는 모든 환경에서 모듈을 하는 것이 목표다. exports 키워드로 모듈을 만들고 require() 함수로 불러 들이는 방식이다. 대표적으로 서버 사이드 플랫폼인 Nodejs에서 이를 사용한다.

 

export function sum(a,b) { return a + b;}

내보낼 때는 export를 사용한다.

 

import * as math from './math.js'

가져올 때는 import를 사용한다.

 


 

AMD : 비동기로 로딩되는 환경에서 모듈을 사용하는 것이 목표다. 주로 브라우저 환경이다.

UMD : AMD 기반으로 CommonJS 방식까지 지원하는 통합 형태다.

이렇게 각 커뮤니티에서 각자의 스펙을 제안하다가 ES2015에서 표준 모듈 시스템을 내놓았다. 지금은 바벨과 웹팩을 이용해 모듈 시스템을 사용하는 것이 일반적이다. ES2015 모듈 시스템의 모습을 살펴보자.

 

😀 html 브라우저

<script type="module" src="src/math.js"></script>

이렇게 되면 script 구문 안에 type="module" 을 입력 해야한다. 하지만 이럴 때는 서버를 돌려야 되는데, npm으로 lite-server를 설치해준다.

 

$npx lite-server

위 명령어로 설치해주면 현재 폴더를 서버로 만들어준다. 그럼 자동으로 브라우저가 켜지면서 app.js 파일에 import 시킨 math.js 파일의 수식들이 계산되어 나온다.

 

👩🏻 프로젝트나 클론코딩 할 때마다 개발환경에 대한 지식이 미흡했는데 인프런 김정환님의 강의를 보면서 그동안 알고 싶었던 웹팩, 바벨, esLint, 프리티어에 대해 공부 시작해보자. 이렇게 개발환경에 대해 잘 알아두면 협업 할 때나 개발환경을 커스터마이징 할 수 있어서 나에게 편한 개발환경을 구축해 나갈 수 있다는 것이 정말 필요할 것 같고 웹팩과 eslint는 요즘 채용공고에 뜨는 기업들의 우대사항에 있어 빼놓을 수 없는 부분인 듯 하다.

 

FN개발에 node.js가 필요한 이유

1. 최신 스펙으로 개발할 수 있다

타입스크립트나 scss같은 고수준 프로그래밍 언어를 사용하려면 전용 트랜스파일러가 필요하다. 이런 것도 노드.js 환경이 뒷받침 돼야 프론트앤드 개발 환경을 만들 수 있다.

2. 빌드 자동화

파일을 압축하고, 코드를 낙독화하고, 폴리필을 추가하는 등 개발 이외의 작업을 거친후 배포한다. node.js는 이러한 일련의 빌드 과정을 이해하는데 적지 않은 역할을 한다.  뿐만 아니라 라이브러리 의존성을 해결하고, 각종 테스트를 자동화 하는데도 사용된다.

3. 개발 환경 커스터마이징

리액트 CRA를 사용하면 손쉽게 개발환경을 갖출 수 있다. 하지만 개발 프로젝트는 각자의 형편이라는 것에 있어서 툴을 그대로 사용할 수 없는 경우도 빈번하다. 커스터마이징을 하려면 Node.JS 지식이 필요하다. 어쩌면 자동화된 도구를 사용할 수 없는 환경이라면 직접 환경을 구축해야 할 상황에 놓일 수도 있다. 이러한 배경하에 Ndoe.js는 프론트엔드 개발에서 필수 기술로 자리매김하고 있다. 

node 설치 (https://nodejs.org)

페이지에 들어가서 본인 운영체제에 맞는 파일을 다운로드 하면 된다. 후에 터미널 창을 켜서 node를 검색하면 node가 실행된다. 이런 터미널창을 REPL 이라고 부른다. 자바스크립트 코드를 입력하고 즉시 결과를 확인할 수 있다.

{
  "name": "fn_dev_env",
  "version": "1.0.0",
  "description": "<br>",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "leehyunju",
  "license": "ISC"
}
  • name : 프로젝트 이름
  • version : 버전 정보
  • description : 내용
  • main : node.js에서 쓰이는 거라 무시해도 된다.
  • scripts : 프로젝트를 자동화 할 수 있는 스크립트를 입력하는 부분
  • author : 프로젝트 작성자
  • license : 라이센스 정보
 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },

여기서 test는 터미널창에 `프로젝트 이름 test` 입력하면 밑에처럼 나온다.

 

echo 명령어로 `no test specified`라는 문구가 출력됐고, 1번 에러코드를 반환했기 때문에 에러메시지가 나오는 것을 확인할 수 있다. && exit 1 이 에러코드를 반환하겠다는 뜻.

 

터미널창에 npm command를 입력하면 우리가 자주 사용하는 command 명령어가 나온다. 특히 이중에서 start, install, test 를 가장 많이 사용. 기본으로 제공되는 command외에 다른 command를 추가하고 싶다면,

 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build":"echo \"여기에 빌드 스크립트를 추가합니다\""
  },

스크립트 부분에 "build"를 입력하면 된다.

 

npm run build를 입력하면 스크립트 부분에 build로 등록했던 문장이 출력된다.

NodeBird.propTypes = {
    Component: PropTypes.elementType.isRequired,
}

👩🏻 리액트 코딩할 때 'prop-types' 라이브러리를 설치하지 않아도돼고 위 코드처럼 propTypes를 선언해주지 않아도 돼서 편하다.  propTypes는 전달받은 데이터의 유효성을 검증하기 위해 다양한 유효성 검사기를 내보내는데, 만일 prop에 유효하지 않은 값이 전달 되었을 때, 경고문이 자바스크립트 콘솔을 통해 보인다. 반면에 타입스크립트는 에러가 나는 즉시 바로 에러를 체크 해주는 점도 베스트였다. 에러난 구문에 마우스 커서를 올리면 에러가 날 때 어떻게 고쳐나가야 될 지도 친절하게 알려준다. 이처럼 타입스크립트는 일반적인 오류를 최대한 많이 검출하면서 올바른 프로그램을 만들 수 있게 설계되었다 ! 이러니 요즘 많이 쓰는 추세인 듯 하다 👏🏻 하지만, 타입스크립트를 생성할 때마다 일일이 js파일로 컴파일 해줘야한다는 점이 번거롭기 때문에 다음에는 웹팩과 eslint 등등 웹 개발 환경 세팅하는 방법에 대해서 공부하기!

 

{
  "compilerOptions": {
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": true,
    "target": "es5",
    "outDir": "dist"
  },
  "include": [
    "scripts/**/*"
  ]
}
  • 포함은 TypeScript(*.ts) 파일을 찾을 수 있는 위치를 컴파일러에 알려줍니다.
  • outDir 옵션은 TypeScript 컴파일러에 의해 트랜스파일된 일반 JavaScript 파일의 출력 폴더를 지정합니다.
  • sourceMap 옵션은 컴파일러에서 sourceMap 파일을 생성할지 여부를 나타냅니다.

 

🎈 컴파일러 옵션

# tsconfig.json에 대한 fs를 역방향으로 검토하여 컴파일 실행
tsc

# 컴파일러 기본값으로 index.ts만 트랜스파일
tsc index.ts

# 기본 설정으로 src 폴더 안에 모든 .ts 파일을 트랜스파일
tsc src/*.ts

# tsconfig.json의 컴파일러 설정으로 src 폴더 안에 모든 .ts 파일을 트랜스파일
tsc --project tsconfig.json src/*.ts

 

typescript-kr.github.io/

 

TypeScript 한글 문서

TypeScript 한글 번역 문서입니다

typescript-kr.github.io

 

🎈 타입스크립트 모듈화란?

타입스크립트에서 가르키는 모듈이라는 개념은 ES6의 모듈과 개념이 유사하다. 모듈은 전역 변수와 구분되는 자체 유효 범위를 가지며 export. import와 같은 키워드를 사용하지 않으면 다른 파일에서 접근할 수 없게 된다.

 

🎈 Import & Export

임포트와 익스포트는 자바스크립트의 코드를 모듈화 할 수 있는 기능이다. 여기서 모듈화란 쉽게 말해 다른 파일에 있는 자바스크립트의 기능을 특정 파일에서 사용할 수 있는 것을 의미한다.

 

🎈 모듈화의 필요성

기본적으로 자바스크립트의 유효 범위는 전역으로 시작한다.

 

🎈 기본 문법

export 변수, 함수

다른 파일에서 가져다 쓸 변수나 함수의 앞에 export라는 키워드를 붙혀 사용한다.

import {불러올 변수 또는 함수 이름} from '파일 경로';

 익스포트된 파일음 import로 불러와 사용할 수 있다.

 

🎈 타입스크립트 모듈화 예시

[types.ts]

export interface Todo {
  title: string,
  checked: boolean,
}

 

[app.ts]

import { Todo } from './types';

var item: Todo = {
  title: '할 일1',
  checked: false,
}

types.ts 라는 파일에 인터페이스를 다른 파일에 사용할 수 있도록 export[내보내기] 해주고, app.ts라는 파일에서 types를 import 시켜서 item 변수에 인터페이스 타입들을 불러왔다.

🎈 타입호환 이란?

타입스크립트 코드에서 특정 타입이 다른 타입에 잘 맞는지를 의미한다. 타입스크립트가 코드를 해석해 나가는 과정에서 두 개의 타입이 서로 호환이 되는지를 점검하는 것을 타입 호환성이라고 한다. 

interface Developer {
  name: string;
  skill: string;
}
interface Person {
  name: string;
}
var developer: Developer;
var person : Person;

person = developer;

이렇게 Developer와 Person의 인터페이스를 생성하고 중복되는 속성은 name뿐이다. Developer는 name과 skill이라는 속성이 총 2개나 있고, Person은 name이라는 속성 1개뿐. 만약 위에는 인터페이스를 선언하고 아래는 클래스를 선언해도 실제로 이 두 개의 타입은 같다고 한다. 타입에 정의되어 있는 타입을 가지고 실제로 호환 되는지를 점검하는데 이런 것을 공식문서에서는 구조적 타이핑이라고 한다.

 

이렇게 됐을 때,

person = developer;

이처럼 오른쪽에는 더 많은 속성을 가지고 있거나 더 큰 관계를 갖고 있을 때에 왼쪽과 호환이 된다.  더 객체가 많은 속성을 가진, 구조적으로 더 큰 관계를 갖고 있기 때문이다.

 

🎇 다른 예시 01

var add = function(a: number) {
  console.log(a);
}

var sum = function(a: number, b: number) {
  return a + b;
}

여기서 add와 sum의 차이점은 sum함수가 파라미터 한 개가 더 들어있다. 그래서 sum이라는 함수 자체가 add라는 함수보다 더 크다고 볼 수 있다. 크다라는 의미는 추가적으로 옵션들을 더 제공한다.

 

🎇 다른 예시 02

interface Empty<T> {

}
var empty1: Empty<string>;
var empty2: Empty<number>;
empty1 = empty2;
empty2 = empty1;

맨 위에 인터페이스는 안에 값이 비어있어서 어떤 값이 들어와도 동일한 타입이라고 간주한다. 

 

🎇 다른 예시 03 : 제네릭

interface NotEmpty<T> {
  data:T;
}
var notEmpty1: NotEmpty<string>;
var notEmpty2: NotEmpty<number>;
notEmpty1 = notEmpty2;
notEmpty2 = notEmpty1;

이렇게 제네릭으로 인터페이스 호출해주면 타입이 바뀐걸로 간주되어 서로 타입 호환이 되지 않아 에러가 난다.

🎈 타입 단언 알아보기

var a;

이렇게만 선언한 a에 대한 타입은 any가 되고

a = 20;

이렇게 숫자로 대입한 a는 숫자로 추론이 된다.

a = 'a';

얘는 문자열로 추론이 된다.

var b = a;

얘는 원래같으면 맨 처음에 선언된 any가 b에 할당된다.

var b = a as string;

이렇게 as 키워드를 사용하여 후에 타입을 선언하면 선언 한 타입(string)으로 지정된다. 이처럼 타입 단언은 타입스크립트보다 개발자가 타입을 더 잘 알고있다라는 의미로 타입스크립트 너는 신경쓰지 말고 내가 정한 타입에 간주하라... 요런 너낌으로 받아들이면 된다.

 

🎈 DOM API 조작

<div id="app">hi</div>

var div = document.querySelector('div');

if (div) {
  div.innerText
}

웹페이지에 태그를 조작해줄 때 가장 많이 사용하는 API는 querySelector이다. 그리고 위 코드처럼 DIV라는 변수에 담아 태그에 접근하면 알아서 HTMLElement라고 추론해준다. 그리고 if문으로 div가 있는지 확인을 하고 그 다음에 조작을 해주는게 일반적인 타입단언의 패턴이다. div라는 값이 null일 수도 있기 때문에 밑에 호출된 div가 어떤 걸 데려오는지 div가 있는지를 if문을 통해 확인해보는 것이다.

 

그래서 이때,

var div = document.querySelector('div') as HTMLDivElement;
div.innerText;

이렇게 as라는 키워드를 사용하여 미리 HTMLElement로 타입을 단언해주는 것이다. as를 쓰는 시점에는 코드가 돌아갈 때 querySelector가 HTMLElement라고 단언해준다. 

 

🎈 타입 가드 알아보기

interface Developer {
  name: string;
  skill: string;
}

interface Person {
  name: string;
  age: number;
}

function introduce(): Developer | Person {
  return { name: 'Tony', age: 33, skill: 'Iron Making'}
}

var Tony = introduce();
console.log(Tony.name);

if ((Tony as Developer).skill) {
  var skill = ((Tony as Developer).skill);
  console.log(skill);
} else if ((Tony as Person).age) {
  var age = (Tony as Person).age;
  console.log(age);
}

인터페이스 선언해주고, introduce라는 함수에 유니온 타입으로 작성하여 Tony를 호출해줬다. 그리고 if문을 사용하여 타입 단언 방식으로 as를 써가며 타입이 있나 없나 확인하는 과정이다. 첫 줄에는 Tony as Developer를 사용하여 디벨로퍼에  skill이 있나 없나 확인을 한 후에 있으면 또 skill이라는 것을 호출해주도록 변수에 담는 이 과정을 반복해서 만들었다. 이렇게 하면 가독성도 떨어지고 여러번 선언해야 된다는 불편한 점이 있어 이것을 보완한 것이 타입 가드이다.

 

🎈 타입 가드 정의

function isDeveloper(target: Developer | Person): target is Developer {
  return (target as Developer).skill !== undefined;
}
if (isDeveloper(Tony)) {
  console.log(Tony.skill) 
} else {
  console.log(Tony.age) 

타입가드 함수는 is라는 패턴과 target이라는 키워드를 사용한다. 그리고 skill이라는 값이 있을 때 !== undefined 함수를 사용했다. if문은 토니가 Developer이면 스킬을 제공해준다. 그렇지 않으면 토니는 Person으로 인식하여 age를 제공해준다. if문 첫 줄에는 developer가 토니이고, 밑에줄은 Person으로서의 토니이기 때문에 각각의 필요한 속성을 접근할 수 있다.

 

🎈 타입추론 특징

let x = 3;

위와 같이 x 변수가 따로 타입을 지정하지 않더라도 일단 x는 3이라는 수식어가 들어있기에 number 타입으로 간주된다. 이렇게 변수를 선언하거나 초기화 할 때 타입이 추론된다. 이외에도 변수, 속성, 인자의 기본값, 함수의 반환값 등을 설정할 때 타입 추론이 일어난다.

var a = 'abc';

function getB(b = 10) {
  var c = 'hi';
  return b + c;
}

변수 C의 속성은 'hi' 라는 문자열이 들어있어 타입이 알아서 string 문자열로 자동 추론된다.

그리고 반환값은 b + c 인 경우

b: number, c:string

으로 간주되어 출력되는 값은 //10hi 로 출력된다. 그리고 getB 파라미터에 타입을 정의되지 않은 채 b만 정의가 될 경우 알아서 any라는 타입으로 정의해준다.

 

🎈 타입추론 기본 예제 02

interface Dropdown<T> {
  value: T;
  title: string;
}

var shoppingItem: Dropdown<string> = {
  value: 'abc',
  title: 'hello',
}

인터페이스와 제너릭을 이용한 타입 추론 방식이다. T에 따라서 value값이 변경 될 수도 있다. title이란 속성값은 string으로 고정시켜 놓았으니 그 타입 고대로 Fix 된 것. 그리고 다른 함수를 선언하면서 변수를 초기화 하면 타입도 초기화 된다. 위 코드처럼 value값에 'abc'를 넣으면 자동으로 문자열로 변동되고 숫자를 넣으면 자동으로 number 타입으로 변동된다.

 

🎈 타입추론 기본 예제 03 : 복잡한 구조에서의 타입 추론 방식

interface Dropdown<T> {
  value: T;
  title: string;
}

interface DetailedDropdown<K> extends Dropdown<K> {
  description: string;
  tag: K;
}

var DetailedItem: DetailedDropdown<string> = {
  title: 'hello',
  description: 'ab',
  value: 'a',
  tag: 'a'
}

처음에는 인터페이스로 제너릭을 선언해주고 value값도 T 제너릭 형태로 타입정의. 그리고 또 다른 인터페이스를 선언할 때는 Dopdown 인터페이스를 extends(확장) 키워드를 써서 데려오면 굳이 선언하지 않아도 암묵적으로 Dropdown에 있는 속성들이 들어와있다. (value, title) 그리고 새로운 DetailedItem 함수를 생성할 때 DetailedDropdown을 가져옴과 동시에 즉시 타입을 지정해주면 위에 있는 인터페이스들 value값들이 자동으로 string으로 변동된다. 그리고 DetailedItem 변수에 담긴 속성들은 문자열로 나열해주어야 에러를 방지할 수 있다.

 

🎈 가장 적절한 타입

타입은 보통 몇 개의 표현식을 바탕으로 타입을 추론한다. 그리고 그 표현식을 이용하여 가장 근접한 타입을 추론하게 되는데 이 가장 근접한 타입을 Best Common Type이라고 한다.

  • 예제
let arr = [0, 1, null];

배열에 들어가는 값들이 한 타입으로 통일되지 않았다. 2개는 숫자형, 1개는 논리형으로 들어가있는데 위 코드처럼 선언 후 arr 변수 위에 마우스 커서를 올려 놓으면 number | boolean 값으로 알아서 유니온 방식으로 추론해준다.

+ Recent posts