TypeScript 사용자의 Flow 탐험기 (2) — 기본 타입 사용해보기

Mark Lee (이웅재)
8 min readOct 29, 2018

--

앞선 포스팅 에서는 Flow 를 설치하고, VSCode 에서 사용할 수 있도록 설정해보았다. 이제 Flow 를 사용할 준비가 되었으니, Flow 가 JavaScript 에서 어떤 방법으로 정적 타입 체커 역할을 하는지 차근차근 짚어볼 생각이다.

타입을 쓰고, 체크하는 과정에 대해 알아 볼 것이기 때문에, 컴파일은 하지 않는다. 그러므로 flow-remove-types 나, babel 과 같이 컴파일러 역할을 하는 패키지는 설치하지 않는다.

flow-bin 패키지만을 설치해서, Flow 의 문법은 어떤지 확인해보자. 무슨 소린지 잘 모르겠으면, 이전 포스팅으로 ㄱㄱ

“나는 이 파일에서 flow 를 실행하여, 정적 타입 체크 할 것이다 !”

확장자로 컴파일할 대상을 구분하는 타입스크립트와는 다르게, Flow 는 아래와 같이 주석 안에 “@flow” 라는 단어를 적는다. 이렇게 적으면, 해당 파일을 정적 타입 체크 하겠다고 설정한 것과 같다.

@flow (나는 이 파일에서 flow 를 실행하여, 정적 타입 체크 할 것이다 !)

몇가지 사소한 주의사항이 있다.

  1. @flow 라는 단어는 한번만 쓸 것. — 여러번 쓰면, 에러가 발생한다.
  2. 코드가 시작하기 전에 쓸 것. (최상단) — 코드가 먼저 나오면 그 코드는 체크하지 않는다.
  3. 주석의 형태는 상관없이, @flow 라는 단어만 있으면 문제 없음.

자 이제 파일을 만들고 최상단 주석에 @flow 라고 적은 뒤, 타입을 적어보자.

Type Annotations

타입을 적는 방법은 얼핏 보기에 타입스크립트와 다르지 않다. 1) 변수나, 2) 함수의 인자, 3) 함수의 리턴 등에 콜론(:)을 붙이고, 타입을 적으면 된다.

src/index2.js (참 쉽죠 ? )

간단하게 타입을 붙이는 법을 확인했으니, 바로 가장 기본이 되는 타입들을 확인해보자.

JavaScript 에도 타입이 있다. 크게 두 가지로 나뉘는데, 하나는 기본 자료형인 Primitive 타입이고, 나머지 하나는 Object 타입이다.

오늘은 Primitive 타입에 대해 알아보자!

Primitive Types

JavaScript 의 Primitive 타입은 아래 목록에 나온 것처럼 6가지 이다. 이 6가지 Primitive 타입 중 Symbols 는 아직 Flow 에서 지원하지 않지만, 나머지는 똑같이 타입으로 사용할 수 있다.

  • Booleans
  • Strings
  • Numbers
  • null
  • undefined (void in Flow types)
  • Symbols (new in ECMAScript 2015, not yet supported in Flow)

보통 JavaScript 에서 Primitive 타입의 값은 리터럴 값으로 사용한다. — ‘hello’
이럴때 타입은 소문자로 시작하도록 표기 하는데,
(나는 잘 안하지만) Primitive 타입의 값을 Wrapper 객체로 생성해서 사용하기도 한다. — new String(‘world’)
이런 경우에는 그 타입을 대문자로 시작하도록 표기한다.
Flow 에서는 이 두가지 방식을 서로 다른 타입으로 이해하며, 그래서 그냥은 서로에게 값을 할당할 수 없다.

타입스크립트에서도 이렇게 대문자, 소문자를 사용해서, 똑같이 리터럴 값의 Primitive 타입과 Wrapper 객체로 생성한 Primitive 타입을 표현한다.
이 부분에서 Flow 와는 다른 부분이 있다. Wrapper 객체로 생성한 Primitive 타입에 리터럴 값의 Primitive 타입을 할당할 수 있다. (반대로 할당은 불가능)

또 한가지 체크할 것은, Flow 는 undefined 를 값으로만 사용한다는 것이다. 그래서 값이 undefined 인 경우, 타입은 undefined 가 아니라 void 를 사용한다.

src/index3.js (flow 의 Primitive Types)

위 코드에서 마지막 두줄이 에러가 나는 부분인데, 별로 중요한 부분은 아니다. 😆
Flow 와 타입스크립트 모두 Primitive 타입을 사용할 때는 리터럴 값으로 된 타입을 사용하는 것을 권장하고 있으며, 실제로 우리는 주로 그렇게 사용하기 때문이다.
(타입스크립트는 심지어 오류메세지에 “가능하면 리터럴 쓰시지” 라고 안내한다.)

Maybe Types

메이비 타입이라는게 있어서 이게 뭘까 싶었다.
물음표가 있어서 옵셔널 타입인가 싶었는데, 물음표의 위치가 콜론(:)의 앞이 아니라 뒤다.

이 부분은 타입스크립트 사용자는 조금만 읽어보면, 무엇을 말하고자 하는지 파악할 수 있다.

타입스크립트에는 “strictNullChecks” 라는 컴파일 옵션이 있다. 이 옵션을 true 로 설정하지 않으면, 모든 타입은 null 또는 undefined 값을 가질수 있다. (이 옵션은 default 가 false 이다.)
이런 경우, 컴파일러는 어떤 것을 string 타입으로 지정해도, null 이나 undefined 값을 가질 수 있다고 판단한다.

이와 다르게, Flow 는 기본적으로 null 또는 undefined(void) 타입을 명시하지 않으면, 해당 값을 가질수 없다.
만약 직접 null, void 라 타입을 지정하지 않고, null, undefined 값을 할당하고 싶으면, 이 Maybe 타입이라는 기법을 사용하는 것이다.

그래서 “?string” 이란 타입을 지정하면, 그 타입에는 string 값 혹은 null, undefined 값을 할당해도 에러가 나지 않게 된다.

나는 물론 이것을 좋아하진 않는다. 😆

Maybe Types (나는 null 이나, undefined 값을 가질 수 있어!)

Optional properties or parameters

객체의 속성이나, 함수의 파라미터가 있을 수도 있고, 없을 수도 있는 경우에 사용하는 방법이다.
타입스크립트에서도 사용하는 방법이고, 코드를 읽으며 쉽게 이해할 수 있다.

바로 아래 코드를 보자. test 함수의 obj 라는 파라미터는 객체로 그 객체의 프로퍼티인 a 는 있을 경우, string 타입이라는 의미이다.
그래서 아래 호출부를 보면, a 가 있는데, string 타입이 아닌 경우 에러가 발생함을 알 수 있다.
또 한가지 a 라는 프로퍼티가 없다는 것은 a 가 undefined 값을 가질 때와 같아서 마지막 줄처럼 사용할 수도 있다.

src/index5.js (Object 의 프로퍼티를 옵셔널로 지정)

아래는 함수의 파라미터를 옵셔널로 표현한 코드이다. 객체 프로퍼티를 옵셔널하게 지정했을 때와 크게 다르지 않음을 알 수 있다.

src/index6.js (함수의 파라미터를 옵셔널로 지정)

함수의 파라미터에 default 값 지정하기

함수 호출 시, 1) 파라미터에 값을 지정하면, 그 값으로 파라미터를 사용하고, 2) 파라미터에 값을 지정하지 않으면, 미리 지정된 값으로 파라미터를 사용하는 기능이다.

Optional 때와 마찬가지로 파라미터에 값을 지정하지 않는 경우는 파라미터에 undefined 값을 지정할 때와 같다.

src/index7.js (함수의 파라미터에 default 값 지정하기)

타입스크립트와 개념이 크게 다르지 않네요.

혹시 작업한 소스가 필요한 분은 https://github.com/2woongjae/flow.git 를 참고해주세요. 그리고 업데이트로 인해 내용이 맞지 않으면, 알려주세요. 글을 내리던가 수정할게요 😆

--

--

Mark Lee (이웅재)

Microsoft MVP (JavaScript / TypeScript) & Software Engineer @ Studio XID, Inc.