[노마드코더 챌린지 / Typescript로 블록체인 만들기] - day3

Teasan·2022년 6월 29일
0

typescript

목록 보기
7/13
post-thumbnail

2.1 Implicit Types vs Explicit Types


Typescript의 타입 시스템

만약 Javascript만 공부해온 사람이라면 이 Typescript의 타입 시스템이 다소 생경하게 느껴질지도 모른다. Javascript 에서는 변수를 생성하기만 되었지, 그 변수의 타입에 대해서 지정해주지 않아도 되었기 때문이다. 그말인 즉슨, Typescript를 이용하게 된다면, 변수 하나를 작성하더라도 그게 어떤 타입인지 지정해주어야 한다는 뜻이기도 하다.

Typescript는 두 가지 접근 방식을 결합했다

타입스크립트는 데이터와 변수의 타입을 명시적으로 정의할 수도 있고 (1)
혹은 Javascript 처럼 변수만 생성하고 넘어가도 된다 (2)

여기서 좋은 점은, Typescript가 알아서 타입을 추론해준다는 것이다.

Typescript의 타입 추론

간단한 예시를 통해 Typescript의 타입 추론에 대해서 이해해보자.

let a = "hello";

변수 a 를 생성하고, 문자열 "hello"를 할당해보자. 그리고 변수 a에 마우스 커서를 올리면,

이렇게 a를 선언하고 값을 할당하는 것 만으로도 Typescript는 a의 타입을 추론해주고 있음을 알 수 있다. 그리고 동시에 Typescript는 변수 a가 string 타입이어야 한다는 사실 역시 알게 된다.

let a = "hello";
a = "bye";

변수 a의 값을 재할당 했을 때의 경우는 어떨까? 변수 a에 "bye" 라는 문자열을 새로이 할당했다. 할당하더라도 같은 string 타입이기 때문에 타입스크립트는 에러를 발생시키지 않는다.

let a = "hello";
a = 1;

하지만 숫자 타입의 값을 변수 a에 재할당한다면 분명 문제가 생긴다. Typescript 는 변수 a가 string 타입이라는 것을 이미 알고 있는데, 그것과는 맞지 않는 숫자 타입의 1로 재할당을 했기 때문이다. 그리고 여기서 Typescript는 타입 에러 메세지를 띄우게 된다.

적어도 Javascript에서는 가능한 로직이지만, Typescript에서는 타입 에러를 발생시키는 로직인 것이다. 이렇게 Typescript 에서는 타입 추론이 가능하다. 앞서 이야기한 다른 옵션 중("타입스크립트는 데이터와 변수의 타입을 명시적으로 정의") 하나라면 어떨까.

Typescript의 명시적 타입 선언

Typescript의 명시적 타입 선언은 말 그대로 Typescript 에 구체적으로 타입을 말해주는 것이다. 아래의 예시를 보자.

let b : boolean = false;

변수 b의 타입을 boolean 으로 명시했다. 이렇게 구체적으로 명시를 함으로써 Typescript는 변수 b의 타입이 boolean 임을 알게 될 것이다.

그리고 명시된 boolean 타입이 아닌 다른 타입을 할당하면, Typescript 에서는 타입이 다른 걸 알아차리고 타입 에러 메세지를 띄울 것이다.

명시적 타입 선언이 진짜 Typescript 이다.

let b : boolean = false;

명시적 타입 선언을 통한 타입 지정 방식이 진정한 Typescript 라고 말할 수 있을 것이다. 그리고 이러한 명시적 타입 선언의 문법은 Typescript 에서 만든 문법이며 동시에 우리가 Type Checker와 소통하는 방식이기도 하다.

Type Checker 와 소통하는 방법

Type Checker(타입 체커)는 Typescript 에서 타입을 체크해준다. 그리고 이 타입 체커와 소통하는 방법은 앞서 설명한 두가지 방법, 즉 타입을 추론하게 만드는 것(1)과 타입을 구체적이고 명시적으로 선언하는 것(2)이 있다.

// (1) 타입을 추론하게 만드는 방법
let a = "hello";
// (2) 타입을 구체적이고 명시적으로 선언하는 방법
let b : boolean = false;

하지만, 타입 체커에게 타입을 추론하도록 내버려두는 방법을 허용하기 위해서 보통은 명시적 타입 선언 보다는 타입 추론을 하는 방식을 더 선호하기도 한다. 이런 방식을 사용하면 더 쉽게 코드를 작성할 수 있게 되고, 코드도 짧아져 가독성이 높아지기 때문이다. (물론, 이것은 개인의 성향마다 더 선호하는 방법을 선택하면 될 것이다.) 아래의 예시를 보자.

let c = [1, 2, 3];

여기, number 타입의 요소를 담은 배열 변수 c가 있다. 만약 이 배열 변수 c 에 number 타입이 아닌 다른 타입의 요소를 push() 해서 c 에 담으려고 한다면 어떨까?

let c = [1, 2, 3];
c.push('1');

string 타입을 number 타입의 배열 안에 넣으려고 하는 것이기 때문에 이는 타입 에러를 발생시키고, 이로 인해 이 코드는 작동하지 않을 것이다.

let c = [];
c.push('1');

만약 변수 c를 빈 배열로 만들고, number 타입을 담을 예정이라면 어떻게 될지 생각해보자. 다른 타입의 요소가 c 배열 안으로 들어오지 못하도록 미리 보호하는 장치가 필요할 것이다.

let c : number[] = [];

c.push('1');

이럴 때는 당연하게도 '명시적 표현'을 통한 타입 선언이 필요하다. 해당 변수 c 가 빈 배열이 아니라, number 타입의 요소만 담을 수 있는 배열임을 명시해주고 있는 것이고, 이 때문에 c 변수에 number 가 아닌 다른 타입의 요소는 타입 에러를 발생시킬 수 있게 된다. 그러니 이런 때에는 명시적 표현에 의한 타입 지정이 상당히 유용하다. 그러나, 보통 명시적 표현에 의한 타입 지정은 최소한으로 사용하는 게 좋다. 이런 경우를 제외하고는 Typescript가 타입을 추론하도록 만드는 것이 여러모로 훨씬 낫기 때문이다.

const player = {
	name : "david"
}

player 변수는 name 이라는 속성을 가진 객체이다. 그리고 이 name 속성은 문자열 타입으로 추론이 가능한 것을 알 수 있다. 이런 상황에서 player의 name에 접근하여 다른 타입의 값으로 바꾸려고 한다면,

const player = {
	name : "david"
}

player.name = 1

타입 에러가 발생한다. player에 없는 속성인 hello() 함수를 호출한다고 한다면

const player = {
	name : "david"
}

player.hello();

이 경우 역시 타입 에러가 발생한다. 그리고 이 모든 에러는 Typescript에서 타입 추론을 하고 있기에 가능한 일일 것이다.


참조


노마드 코더 ✧ 타입스크립트로 블록체인 만들기 ✧ 챌린지

profile
일단 공부가 '적성'에 맞는 개발자. 근성있습니다.

0개의 댓글