본문 바로가기

TypeScript

[우아한 타입 스크립트 with 리액트] 타입이란

1. 자료형으로서의 타입

모든 프로그래밍 언어는 변수를 선언하는 것부터 시작한다. 프로그래밍 언어에서 변수란 값을 저장할 수 있는 공간(메모리)이자 값을 가리키는 상징적인 이름이다. 개발자는 변수를 선언하고 그 변수에 특정한 값인 데이터를 할당한다.

// 변수선언 과 데이터할당

var name = "zig";
var year = 2022;

이 예시에서는 name과year라는 이름으로 선언한 변수에서 각각 zig와2022 라는 값을 할당하고 있다. 컴퓨터의 메모리 공간은 한정적이다. 따라서 특정 메모리에 값을 효율적으로 저장하기 위해서는 먼저 해당 메모리 공간을 차지할 값의 크기를 알아야 한다. 값의 크기를 명시한다면 컴퓨터가 값을 참조할 때 한 번에 읽을 메모리 크기를 알 수 있어 값을 훼손하지 않고 가져올 수 있다. 예를 들어 메모리에 숫자 타입 값이 할당되어 있다면 자바스크립트 엔진은 이 값을 숫자로 인식해서 8바이트 단위로 메모리 공간에 저장된 값을 읽어올 것이다.

변수에 저장할 수 있는 값의 종류는 프로그래밍 언어마다 다르다. 최신 ECMAScript 표준을 따르는 자바스크립트는 다음과 같은 7가지 데이터 타입(자료형)을 정의한다.

  1. undefined
  2. null
  3. Boolean
  4. String
  5. Symbol
  6. Numeric( Number 와 BigInt )
  7. Object

이와 같은 유형을 데이터 타입 또는 자료형이라고 한다. 데이터 타입은 여러 종류의 데이터를 식별하는 분류 체계로 컴파일러에 값의 형태를 알려준다. 메모리에 저장된 값을 데이터 타입으로 설명할 수 있으며 모든 데이터를 해석할 때 데이터 타입 체계가 사용된다. 메모리의 관점에서의 데이터 타입은 프로그래밍 언어에서 일반적으로 타입으로 부르는 개념과 같다. 개발자는 타입을 사용해서 값의 종류를 명시할 수 있고 메모리를 더욱 효율적으로 사용할 수 있다.

2. 집합으로서의 타입

프로그래밍에서의 타입은 수학의 집합과 유사하다. 타입은 값이 가질 수 있는 유효한 범위의 집합을 말한다.

const num:number = 123;
const str:string = "abc";

function func(n:number) {
	//...
}

func(num);
func(str);//🚨Argument of type 'string' is not assignable to parameter of type 'number'

어떤 값이 T 타입이라면 컴파일러(또는 개발자)는 이 값으로 어떤 일을 할 수 있고, 어떤 일을 할 수 없는지를 사전에 알 수 있다. 타입 시스템은 코드에서 사용되는 유효한 값의 범위를 제한해서 런타임에서 발생할 수 있는 유효하지 않은 값에 대한 에러를 방지해준다.

위의 예시에서는 func()이라는 함수의 인자로 number 타입 값만 할당할 수 있도록 제한되어 있다. 따라서 number 의 집합에 속하지 않는 string 타입의 str 을 func()함수의 인자로 사용하면 에러가 발생한다. 마치 집합의 경계처럼 func()함수의 인자로 들어갈 수 있는 값을 number 타입의 집합으로 제한하는 것이다.

함수 인자에 들어갈 값의 타입을 정의하지 않은 경우를 살펴보자. 다음과 같이 인자로 받은 값에 2를 곱해 반환하는 함수가 있다고 하자.

function double(n){
	return n*2;
}

double(2); // 4
double("z"); // NaN

double()의 내부 동작을 살펴보면 숫자를 인자로 받을 거라고 기대한다는 것을 알 수 있다. 만약 인자로 숫자가 아닌 다른 타입 값을 전달하면 의도치 않은 작업을 수행해서 원하는 값을 얻지 못한다. 하지만 함수의 매개변수 타입을 명시한다면 올바르지 않은 타입의 값으로 함수를 호출했을 때 타입스크립트의 컴파일러는 곧바로 에러를 발생시킨다.

function double(n:number){
 return n*2;
}

double(2); // 4
double("z"); // 🚨Error: Argument of type 'string' is not assignable to parameter of type 'number'(2345)

3. 정적 타입과 동적 타입

만약 자바스크립트만을 사용했다면 변수와 값을 다룰 때 타입은 고려하지 않고 코드를 작성했을 수도 있다. 그러나 자바스크립트에도 분명히 타입이 존재한다. 다만 개발자가 컴파일 이전에 타입을 직접 정의해줄 필요가 없었을 뿐이다. 타입을 결정하는 시점에 따라 타입을 정적 타입( Static Type ) 과 동적 타입( Dynamic Type )으로 분류할 수 있다.

정적 타입 시스템에서는 모든 변수의 타입이 컴파일타임에 결정된다. 코드 수준에서 개발자가 타입을 명시해줘야 하는 C, Java, Typescript 등이 정적 타입 언어에 속한다. 조금 번거롭게 느껴지기도 하지만 컴파일타임에 타입 에러를 발견할 수 있기 때문에 프로그램의 안정성을 보장할 수 있다.

동적 타입 시스템에서는 변수 타입이 런타임에서 결정된다. Python, Javascript 가 대표적인 동적 타입 언어로 개발자는 직접 타입을 정해줄 필요가 없다. 프로그램을 실행할 때 타입 에러가 발견되기 때문에 개발 과정에서 에러 없이 마음껏 코드를 작성할 수 있지만 언제 프로그램에 오류가 생길지 모르는 불안감에 휩싸이게 된다.

function multiplyByThree(number){
	return number * 3;
}

multiplyByThree(10); // 30
multiplyByThree("f"); // NaN

런타임에서 타입을 예측할 수 없다면 매우 위험한 상황이다. 다음 예를 살펴보자. multiply-ByThree() 함수 인자로 들어올 값의 타입을 number라고 가정하고 연산을 수행할 때 실제로 런타임에 입력되는 변수가 string타입 값을 갖고 있다면 예상치 못한 결과를 반환해서 오류가 발생한다.

💡 컴파일 타임과 런타임 개발자가 작성한 소스코드를 실행하려면 몇 가지 과정을 거쳐야 하는데 시점에 따라 컴파일타임과 런타임으로 구분할 수 있다.
컴파일 타임( Compile Time ) 기계(컴퓨터, 엔진)가 소스코드를 이해할 수 있도록 기계어로 변환되는 시점
런타임 ( Runtime ) 컴파일 타임 이후 변환된 파일이 메모리에 적재되어 실행되는 시점으로 해당 프로그램이 필요한 시스템 자원(RAM, 시스템 변수, 환경변수 등)을 할당받고 실제로 시스템 자원을 사용해서 어떤 처리를 하고 있는 것을 의미한다.
런타임 환경( RTE, Runtime Environment ) 런타임이 일어나기 위해, 즉 해당 프로그램(애플리케이션)이 시스템 자원을 사용하기 위해 시스템 자원에 액세스 할 수 있도록 해주는 실행 환경으로 런타임 환경없이는 애플리케이션은 시스템 자원에 접근할 방법이 없다. 이러한 런타임 환경은 운영체제 자체에 속하는 경우도 있고 운영체제 위에서 작동하는 소프트웨어 일 수도 있다.