[TS] 타입스크립트의 '타입'

손규성·2022년 12월 1일
0

typescript

목록 보기
1/2
post-thumbnail

타입스크립트, 왜?


타입스크립트는 마이크로소프트에서 자바스크립트의 단점을 일부 보완하기 위해 만든 자바스크립트의 슈퍼셋(Superset) 프로그래밍 언어이며, 타입스크립트 코드는 자바스크립트로 컴파일되기 때문에 자바스크립트가 동작하는 모든 곳에서 사용 가능하다.

동적 타입 언어(Dynamically Typed Language) 인 자바스크립트는 빠른 런타임 속도 대신 타입 안전성이 떨어진다는 단점이 있다. 즉, 개발자가 의도한 바와 다른 타입의 값이 변수에 할당되어도 런타임 전까지 에러를 발견하기 힘들다는 뜻이다. 코드의 길이가 짧은 개인 프로젝트의 경우 굳이 타입스크립트를 고수할 필요는 없겠지만, 자바스크립트만으로 큰 스케일의 프로젝트를 다루는 경우 예상치 못한 경우의 에러를 디버깅하는 과정의 난이도가 한 층 높아진다.

반면 타입스크립트는 이름에 명시되어 있듯 타입을 선언할 수 있는 정적 타입 언어(Statically Typed Language) 이다. 앞서 언급했듯이 타입스크립트 코드는 결국 자바스크립트로 컴파일 되기 때문에 전체적인 런타임 속도는 낮아지지만, 각 변수, 객체 별로 타입을 지정할 수 있다는 점에서 개발자에게 안정성을 보장해준다.


타입스크립트 타입 선언


💡기본 타입

타입스크립트와 자바스크립트의 문법은 상당히 유사하지만, 자바스크립트와 달리 타입스크립트에서는 타입을 지정해주어야 한다는 점이 가장 큰 차이라고 할 수 있다. 자바스크립트에서 변수를 선언할 때는 다음과 같이 코드를 작성할 수 있다.

let message = "Hello World!";

console.log(message); //Output: Hello World!
console.log(typeof message) //Output: string

당연히 Hello World! 라는 문자열을 입력받았기 때문에 현재 message의 타입은 string이다. 자바스크립트에서는 굳이 message라는 변수를 선언할 때 타입을 지정해주지 않아도 된다. 또한 자바스크립트에서는 message 타입을 자유롭게 변경할 수 있다. 아래 예시를 통해 보여지듯 이미 string 타입 값이 할당된 변수를 한 순간 number 타입으로 재할당할 수 있다.

let message = "Hello World!";

console.log(message); //Output: Hello World!
console.log(typeof message) //Output: string

message = 10;

console.log(message); //Output: 10
console.log(typeof message); //Output: number

반면 타입스크립트로 변수를 선언하는 경우에는 각 변수의 타입을 선언해주므로, 이러한 자바스크립트의 유연함이 적절히 제어되게 된다.

콘솔창에 각 messagetypeof message를 출력해보면 자바스크립트 코드와 동일한 결과를 내뱉어주는 것을 확인할 수 있다. 다만 변수 선언 과정에서 변수명 뒤에 :string을 적어두어 message 변수의 타입을 명시해주었고, 이로 인해 값이 변하더라도 string 타입 값만 할당될 수 있도록 변수 범위를 조여준다. 덕분에 자바스크립트 예시와 같이 message에 숫자 10을 재할당하려고 하면 컴파일 과정에서 에러가 발생하는 것을 확인할 수 있다.

마찬가지로 모든 변수에 타입을 선언해서 예상치 못한 에러를 사전 방지할 수 있다.


💡객체 타입

타입스크립트에서는 객체에도 타입을 선언할 수 있다. 유저의 name, age, employmentStatus 정보를 담고 있는 객체가 있다고 가정해보자. 해당 객체는 name에 문자열, age에 숫자, employmentStatus에 boolean 값을 담고 있어야 할 것이다. 이를 바탕으로 객체의 타입을 interface을 통해 선언할 수 있다.

이후 인터페이스 값을 userA 객체와 userB 객체의 타입으로 선언했을 때, 각 프로퍼티의 값이 인터페이스 내에서 선언된 타입과 맞지 않을 때 에러를 띄우게 된다. 아래 예시에서는 userB의 age에 문자열, employmentStatus에 숫자가 입력되자 빨간줄로 표시된 것을 확인할 수 있다.

동일하게 인터페이스를 통해 약속된 값이 입력되지 않은 경우에도 타입스크립트는 에러를 뱉게 된다. 만약 선택적으로 받을 값이 있다면 key?: type 문법을 사용하면 된다. 아래 예시의 경우 userC에 employmentStatus 값이 존재하지 않는다. 인터페이스를 통해 employmentStatus라는 프로퍼티가 약속되었기 때문에 userC가 빨간줄로 표시된 것을 확인할 수 있다.

반면 userInfoType 인터페이스 내에서 employmentStatus?: boolean 으로 코드를 수정하면, employmentStatus는 있을 수도 있고 없을 수도 있는 프로퍼티로 변경된다. 따라서 존재하는 경우에만 값이 boolean 타입인지 확인하기 때문에, 애초에 employmentStatus 프로퍼티를 가지고 있지 않은 userC 객체에는 에러가 발생하지 않는다.


💡배열 타입

마찬가지로 타입스크립트는 배열의 타입도 제어할 수 있다. 첫 번째로 배열의 길이는 제어하지 않고 배열 내 데이터의 타입만 제어할 때는 배열명: type[] 문법을 활용하면 된다. 이렇게 배열 타입을 선언하는 경우, 해당 배열 안에 들어가는 값은 무조건 선언된 타입과 일치해야 한다. 아래 예시를 살펴보자.

array1에서 array3 까지는 단일 타입의 데이터만 받는 배열이다. 각 string, number, boolean 값만 받을 수 있으며, 이외의 값을 입력하는 경우에는 에러로 이어지게 된다. array4의 경우 유니언 타입을 선언했다. 즉, array4는 string 및 number 값을 받을 수 있는 것이다. 각 배열에 선언된 타입 외의 값을 넣는 경우 타입스크립트에서 에러를 발생시키는 것을 확인할 수 있다.

반면 배열의 길이와 데이터 타입을 동시 제어하는 방법도 있다. 이를 Tuple 타입이라고 한다. Tuple 타입을 사용하기 위해서는 배열명: [type, type, type...] 문법을 사용하면 된다. 아래 예시를 보면 tupleArray라는 배열의 타입을 [string, number, boolean]으로 선언했다. 이런 경우 tupleArray의 길이는 3, 각 데이터는 동일 인덱스에 위치한 타입과 일치해야 한다. 그렇지 않은 경우 tupleArray2처럼 타입과 일치하지 않는 데이터에 에러가 표시되게 된다.


💡함수 타입

타입스크립트를 통해 함수가 받을 매개변수 및 반환 값의 타입을 선언해두어 에러를 방지하고 함수의 가독성을 높일 수 있다. 아래 예시처럼 a, b를 매개변수로 받는 함수를 작성했다고 가정해보자. 이런 경우 a와 b를 number 타입으로 가져와주고, 데이터를 가공해서 string으로 반환하고자 할 때 아래 예시처럼 코드를 작성하면 된다.

만약 여러 함수가 동일한 매개변수 및 반환 값 타입 형태를 가지고 있다면, 타입 에일리어스(Type Alias) 를 통해 여러 함수에 동일한 타입을 손쉽게 지정할 수 있다.


💡Any, Unknown 타입

Any 타입은 명칭에서 드러나듯 어떠한 타입의 값도 할당 가능하다는 것을 뜻한다. 사실상 타입스크립트를 사용하지 않는 것과 똑같다고 보면 된다. 덕분에 any 타입으로 선언된 변수 userName에는 초기 값인 'James'에서 숫자 10으로, 이후 true로 타입을 뛰어넘는 자바스크립트식 유연한 값 재할당이 가능한 것을 확인할 수 있다. 이러한 이유로 인해 타입스크립트 공식 문서에서도 any 타입의 선언을 권장하지 않는다.

다만 개발을 하다 보면 어떤 타입의 값을 할당해야 하는지 아직 모를 때가 있다. 이러한 경우 any로 타입을 선언하는 것보다 unknown 타입으로 선언하는 것이 더 적절하다. 아래 예시를 보면 unknown 타입으로 선언된 a 변수를 대문자로 변경하려고 하자 타입스크립트가 a에 에러를 표시하는 것을 볼 수 있다. 이렇게 개발하는 도중 특정 메서드 도입 등으로 인해 선언해야 하는 타입이 확정되면 unknown 타입으로 선언되었던 타입을 변경해주는 것이 일반적이다.


💡Void, Never 타입

Void 타입은 어떠한 타입도 존재하지 않는 경우에 사용한다. 주로 함수의 반환 값이 존재하지 않을 때 사용한다. 예를 들어 특정 함수에 return 대신 console.log만 하게 되는 경우 반환될 값이 없으므로 함수의 타입을 지정할 때 void 타입을 선언하는 것이다.

Never 타입은 많이 사용되지는 않지만 void 타입과 비슷하게 어떠한 값도 할당하지 않을 때, 주로 함수의 리턴 타입으로 사용된다. 함수가 무한루프를 돌아야 하거나 에러를 던져야 하는 경우 함수의 끝에 도달하지 않기 때문에 never 타입을 지정해준다. 즉 void 타입은 리턴 값이 없을 뿐이지 함수가 종료되긴 하지만, never 타입의 경우 함수가 종료되지 않음을 가정하고 리턴 값에 선언하는 타입이라 할 수 있다.


💡Symbol 타입

Symbol 타입은 비교적 최근 도입된 number 및 string과 같은 원시 데이터 타입이다. 아래 예시와 같이 Symbol() 문법으로 생성할 수 있으며, 이때 인자로 문자열을 전달할 수 있다. 다만, 해당 문자열은 symbol 타입을 선언하는 데 어떠한 영향도 미치지 않으며, 단순히 디버깅 과정에서 참고할 수 있는 description 값으로 사용된다.

일반적으로 객체의 key로 많이 활용된다. Symbol() 메서드를 호출할 때마다 고유한 값이 생성되기 때문에 객체 내 key 간의 충돌을 방지할 수 있다는 이점이 있다.

profile
블로그 이사 → https://sqsung.tistory.com/

0개의 댓글