본 포스팅은 "타입스크립트 프로그래밍" 책을 읽고 정리한 내용입니다.

타입 - 값과 이 값으로 할 수 있는 일의 집합

위 설명의 예시를 살펴보겠습니다.

  • Boolean 타입은 모든 불(true or false)과 불에 수행할 수 있는 모든 연산(||, &&, ! 등)의 집합이다.
  • number 타입은 모든 숫자와 숫자에 적용할 수 있는 모든 연산(+,-,..), 숫자에 호출할 수 있는 모든 메서드(.toFixed, toPrecision 등)의 집합이다.

위와 같이 타입이란 값, 그리고 값이 할 수 있는 행위의 집합입니다.

따라서 어떤 값이 T 타입이라면, 이 값을 가지고 어떤 일을 할 수 있고 어떤 일을 할 수 없는지도 알 수 있습니다.

이러한 특징을 이용해 타입 검사기가 유효하지 않은 동작이 실행되는 일을 예방하는 것이죠.
타입을 사용하는 간단한 예시를 살펴봅시다.

function squareOf(n) {
  return n * n
}
squareOf(2)
squareOf('z')

위 함수는 형태상 파라미터로 숫자를 받음이 명확하며, 숫자가 아닌 다른 타입이 전달될 경우 유효하지 않은 작업을 수행하게 됩니다.

타입스크립트의 타입을 명시하면 다음과 같아집니다.

function squareOf(n: number) {
  return n * n
}
squareOf(2)
squareOf('z') // 에러 

간단한 예이지만 타입의 핵심 개념을 소개하기에 적합합니다. 이 코드에서 알 수 있는 내용은 다음과 같습니다.

  • squareOf의 매개변수 n은 number로 제한된다.
  • 2 값은 number에 할당할 수 있는(호환되는) 타입이다.

타입 어노테이셔닝 없으면 squareOf의 매개변수에 제한이 없으므로 아무 타입이나 인수로 전달할 수 있습니다. 일단 타입을 제한하면 타입스크립트가 함수를 호출할 때 호환이 되는 인수로 호출했는지 판단합니다.

이를 경계 개념으로 해석할 수도 있습니다. 타입스크립트에 n의 상위 한정값이 number라고 알려주면 squareOf에 전달하는 모든 값은 number 이하여야 합니다. 만약 number 이상의 것이라면 n에 할당할 수 없게 됩니다.(위의 표를 보면 이해가 더 쉽습니다)

지금은 "타입스크립트란 특정 타입만 와야 할 때 이를 명시할 수 있는 언어"라는 사실을 기억해둡시다.

any

any는 타입들의 대부라 할 수 있습니다. 뭐든지 할 수 있지만 꼭 필요한 상황이 아니라면 사용하지 않는 것이 좋습니다.

프로그래머와 타입스크립트 둘 다 타입을 알 수 없는 상황에서는 기본 타입인 any라고 가정합니다. any는 최후의 보루로, 가급적 사용하지 않아야 합니다.

any를 이용하면 값이 자바스크립트처럼 동작하기 시작하면서 타입 검사기라는 마법이 더 이상 작동하지 않게 됩니다. 따라서 되도록 사용을 피하고 반드시 최후의 수단으로만 사용해야 합니다.

any를 사용하려면 명시적으로 선언해야 합니다. 타입스크립트가 어떤 값을 any로 추론해야 하는 상황(함수의 매개변수 타입 정의를 빼먹거나 타입을 사용하지 않는 자바스크립트 모듈을 임포트)이라면 빨간 밑줄과 함께 컴파일 타임 예외가 발생합니다.

명시적으로 any로 설정하면 개발자의 의도하는 바를 알려줄 수 있고 예외도 발생하지 않습니다.

TSC 플래그: noImplicitAny
암묵적인 any가 나타났을 때 예외를 일으키고 싶다면 tsconfig.json 파일에서 noImplicitAny 플래그를 활성화 합니다.
위 플래그는 TSC 플래그의 strict 패밀리에 속하므로, tsconfig.json에서 strict를 활성화했다면 따로 활성화하지 않아도 됩니다.

unknown

타입을 미리 알 수 없는 어떤 값이 있을 때 any 대신 unknown을 사용합니다. any처럼 모든 값을 대표하지만, 타입을 검사해 정제하기 전까지 타입스크립트가 unknown 타입의 값을 사용할 수 없게 강제합니다.

unknown은 비교연산(==, ===, || 등)과 반전(!)을 지원하고, typeof, instanceof 연산자로 정제할 수 있습니다.

let a: unknown = 30 // unknown
let b = a === 123 // boolean
let c = a + 10 // 에러
if (typeof a === 'number') {
  let d = a + 10 // number 
}

위 예시를 통해 unknown의 기본적인 사용법을 알 수 있습니다.

  • 타입스크립트가 무언가의 타입을 unknown이라고 추론하는 상황은 없다. unknown 타입을 사용하고자 한다면 명시적으로 설정해야 한다.
  • unknown 타입이 아닌 값과 unknown 타입인 값을 비교할 수 있다.
  • 하지만 특정 타입이라고 가정하고 동작을 수행할 수 없고, 타입스크립트에게 해당 값이 특정 타입임을 증명해야 한다.(d)

boolean

불 타입은 true, false 두 개의 값을 갖습니다. 이 타입으로는 비교 연산과 반전 연산을 할수 있을 뿐 많은 연산을 지원하지 않습니다.

let a = true // boolean -> ts가 추론
var b = false // boolean -> ts가 추론
const c = true // true -> 어떤 값이 특정 boolean임을 ts가 추론
let d: boolean = true // boolean -> 명시적으로 선언
let e: true = true // true -> 특정 boolean임을 명시적으로 선언
let f: true = false // 에러 -> 특정 boolean임을 명시적으로 선언

실제 프로그래밍에서는 보통 타입스크립트가 추론하는 방식(a,b,c)을 많이 사용합니다. 타입 안정성을 목표로 드물지만 e, f같은 방식을 사용하기도 합니다.

d와 같은 방법은 거의 사용할 일이 없습니다.

특정 값을 타입으로 사용하는 e, f에 사용할 수 있는 값은 boolean 타입이 가질 수 있는 값 중 특정한 하나의 값으로 한정됩니다. 이러한 기능을 타입 리터럴 이라고 부릅니다.

  • 타입 리터럴 - 오직 하나의 값을 나타내는 타입

const를 사용하는 경우 변수의 값이 절대 변하지 않으리라는 사실을 알게 되어 해당 변수가 가질 수 있는 가장 좁은 타입으로 추론합니다.

타입 리터럴은 모든 곳에서 일어날 수 있는 실수를 방지해 안전성을 추가로 확보해주는 강력한 언어 기능입니다.

number

number 타입은 모든 숫자의 집합입니다. 이 타입에서는 덧셈, 뺄셈, 모듈로, 비교 등의 숫자 관련 연산을 수행할 수 있습니다.

let a = 1234 // number -> ts가 추론
let b = Infinity * 0.10 // number -> ts가 추론
const c = 5678 // 5678 -> const를 사용해값이 특정 number임을 ts가 추론
let e: number = 100 // number -> 명시적으로 선언
let f: 26.218 = 26.218 // 26.218 -> 특정 number임을 명시적으로 선언
let g: 26.218 = 10 // 에러 -> 특정 number임을 명시적으로 선언

개발자들은 대개 타입스크립트가 타입을 추론하도록 만듭니다. 상황에 따라 특정 값으로 제한되도록 처리하기도 합니다. number임을 명시적으로 선언하는 상황은 거의 없습니다.

긴 숫자를 처리할 때는 숫자 분리자를 이용해 숫자를 읽기 쉽게 만들 수 있습니다. 숫자 분리자는 타입과 값 모두에 사용할 수 있습니다.

let oneMillion = 1_000_000 // 1000000과 같음
let twoMillion: 2_000_000 = 2_000_000

bigint

bigint는 자바스크립트와 타입스크립트에 새로 추가된 타입으로, 이를 이용하면 라운딩 관련 에러 걱정 없이 큰 정수를 처리할 수 있습니다. number는 2^53 까지의 정수를 표현할 수 있지만, bigint를 사용하면 이보다 큰 수도 표현할 수 있습니다.

bigint타입은 모든 BigInt의 집합으로 덧셈, 뺄셈, 곱셈, 나눗셈, 비교 등의 연산을 지원합니다.

let a = 1234n // bigint
const b = 5678n // 5678n
var c = a + b // bigint
let e = 88.5n // 에러. bigint 리터럴은 반드시 정수여야 함
let f: bigint = 100n // bigint
let g: 100n = 100n // 100n
let h: bigint = 100 // 에러

다른 타입들과 마찬가지로 가능하면 타입스크립트가 bigint의 타입을 추론하도록 해야 합니다.

string

string은 모든 문자열의 집합으로 연결(+), 슬라이스 등의 연산을 수행할 수 있습니다.

let a = 'hello' // string
let b = 'billy' // string
const c = '!' // '!'
let d = a + ' ' + b + c // string
let e: string = 'zoom' // string
let f: 'john' = 'john' // 'john'
let g: 'john' = 'zoe' // 에러

역시 마찬가지로 가능하면 타입스크립트가 string 타입을 추론할 수 있도록 하는 것이 좋습니다.

symbol

symbol은 ES2015에 새로 추가된 기능입니다.

let a = Symbol('a') // symbol
let b: symbol = Symbol('b') // symbol
var c = a === b // boolean
let d = a + 'x' // 에러

const e = Symbol('e') // typeof e
const f: unique symbol = Symbol('f') // typeof f
let g: unique symbol = Symbol('f') // 에러 unique symbol은 반드시 const여야 함
let h = e === e // boolean
let i = e === f // 에러 unique 타입은 겹칠 일이 없음.

기본적인 자료형에 대한 타입을 간단하게 살펴보았습니다. 다음 포스팅에선 객체와 배열,튜플, 열거형, 타입별칭과 유니온, 인터섹션 등의 내용을 살펴보겠습니다.

<출처>

profile
웹 개발을 공부하고 있는 윤석주입니다.

0개의 댓글