:ledger: 타입스크립트 타입과 타입 선언 방법을 알아보자

TypeScript를 사용해서 코드의 오류를 사전에 방지하고 유지보수성을 향상시킬 수 있다. 이번 글에서는 TypeScript의 기본 타입과 선언 방식을 알아보자!

:one: TypeScript의 타입 시스템

TypeScript의 가장 큰 특징 중 하나는 정적 타입 시스템을 제공하는 점이다. 이는 변수나 함수의 타입을 명시적으로 선언하며, 컴파일 시점에 오류를 잡을 수 있도록 해줌

:pushpin: 1-1) 기본 타입 (Primitive Types)

TypeScript는 JavaScript에서 사용되는 기본적인 타입들을 그대로 사용할 수 있다.

  1. string: 문자열 타입
let name: string = "rarrit";
  1. number: 숫자 타입
let age: number = 25;
  1. boolean: 불리언 타입(참/거짓)
let isBoy: boolean = true;
  1. nullundefined: 각각 비어있음을 나타내는 타입
let n: null = null;
let u: undefined = undefined;
  1. any: 모든 타입을 허용하는 타입
let value: any = 1;
value = "rarrit"; // 가능함
  1. void: 반환 값이 없음을 의미하는 타입, 주로 함수에서 사용함
function sayHi(): void {
  console.log("hi");
}

:pushpin: 1-2) 배열과 튜플 (Array & Tuples)

배열과 튜플은 여러 값을 담을 수 있는 자료 구조로, TypeScript에서는 배열의 타입을 명시적으로 선언할 수 있다.

  1. 배열: 배열의 요소 타입을 명시할 수 있음
let numbers: number[] = [1,2,3];
let strings: string[] = ["a", "b", "c"];
  1. 튜플: 고정된 길이와 타입을 가지는 배열
let tuple: [string, number];
tuple = ["rarrit", 30];

:two: 타입 선언 방식

TypeScript에서 타입을 선언하는 방법은 간단하다. 변수를 선언할 때 타입을 명시하거나, 함수를 작성할 때 매개변수와 반환 타입을 지정할 수 있다.

:pushpin: 2-1) 변수 선언 시 타입 지정

변수를 선언할 때 타입을 명시적으로 지정하면, 그 변수는 해당 타입의 값만 할당받을 수 있음

let username: string = "rarrit";
let age: number = 30;
let isBoy: boolean = true;

:pushpin: 2-2) 함수 선언 시 타입 지정

함수의 매개변수와 반환값에 타입을 지정할 수 있으며, 이를 통해 함수를 사용할 때 발생할 수 있는 오류를 사전에 방지함

function add(a: number, b:number): number {
  return a + b;
}

let noneFunc: () => void;
noneFunc = function () {
  console.log('hihi');
};

:pushpin: 2-3) 인터페이스 (interface)

interface는 객체의 구조를 정의할 때 사용한다. 객체의 속성 타입을 명확하게 정의하여 안전한 코드를 작성할 수 있게 해줌

interface Todo {
  title: name;
  completed: boolean;
}

const todo: Todo = {
  title: "todo",
  completed: false;
}

:pushpin: 2-4) 타입 별칭 (Type Aliases)

타입 별칭을 사용하면 특정 타입에 이름을 붙여 사용할 수 있다. 복잡한 타입을 쉽게 재사용 가능함

type ID = number | string;

let userId: ID = 111;
userID = "zzz111" // 가능함

type ExampleType = {};
type StringType = string;
type UnionType = string | number

:pushpin: 2-5) Type alias vs interface

TS Documents 내용을 간략히 설명하면 “둘 다 매우 유사하고 많은 경우 자유롭게 선택할 수 있다!” 이다. 하지만 확장성복잡한 타입 표현에서 차이가 있는데, 아래의 차이점을 보고 상황에 맞게 사용하면 됨

  • 확장성(Extensibility)
    • interface
      • 인터페이스는 항상 확장이 가능하며, 다른 인터페이스를 상속하거나 동일한 이름으로 다시 열어 새로운 속성을 추가할 수 있음
    • type alias
      • 타입 별칭은 한 번 정의되면 다시 열어 새로운 속성을 추가할 수 없으며, 동일한 타입에 새로운 속성을 추가해야 하는 경우 인터페이스가 유리함
interface Hello {
	name: string
}

interface Hello {
	age: number
} // ✅ 가능, Hello 는 name 과 age 모두를 포함하게 됨

type Hello2 = {
	name: string
}

type Hello2 = {
	age: number 
} // 🙅‍♂️ 불가능
  • 복잡한 타입 표현
    • interface
      • 객체 형태의 타입을 정의하는 데에 주로 사용된다.
    • type alias
      • 객체 형태 뿐만 아니라, 유니온 타입, 튜플, 매핑된 타입 등 복잡한 타입 표현에 유리함

:pushpin: 2-6) 구조적 타입 시스템

TypeScript의 타입 시스템은 구조적 타입 시스템이다. 구조적 타입 시스템에서는 값의 형태와 구조에 따라 타입이 결정된다. 즉, 타입이 실제로 어떻게 선언되었는지가 아니라 어떤 프로퍼티와 메서드를 가지고 있는지가 중요함.

  • “만약 어떤 새가 오리처럼 걷고, 오리처럼 소리 내고, 오리처럼 행동한다면, 나는 그 새를 오리라고 부를 것이다.”
  • 같은 개념은 아니지만 Duck Typing의 유래는 구조적 타이핑을 이해하는 데에 도움이 된다.
  • 두 개념 다 간단히 말해서, 똑같이 생겼다면 이름이 뭔지는 모르겠지만, 같은 타입으로 간주한다.

:three: 유니언과 교차 타입 (Union & Intersection Type)

TypeScript는 여러 타입을 결합하거나, 여러 타입을 동시에 만족하는 타입을 정의할 수 있는 유니언과 교차 타입을 제공함

:pushpin: 3-1) 유니언 타입 (Union Type)

하나 이상의 타입을 허용하는 경우 유니언 타입을 사용할 수 있음.

let id: number | string;

id = 010; // number 타입 가능
id = "zeronezero" // string 타입 가능

:pushpin: 3-2) 교차 타입 (Intersection Type)

여러 타입을 결합하여 하나의 새로운 타입을 정의할 수 있음. 교차 타입은 두 가지 이상의 타입을 모두 만족해야 함

interface Skills {
  skill: string;
}

interface Infos {
  desc: string;
}

type Champion = Skills & Infos;

const ezreal: Champion = {
  skill: "비전 이동",
  desc: "노랑 머리 원딜"
}

:fire: 마무리

TypeScript는 정적 타입 시스템을 통해 코드의 오류를 사전에 방지하고, 유지보수성을 높이는 데 큰 도움을 준다. 기본 타입부터 배열과 튜플, 인터페이스와 타입 별칭, 그리고 유니언과 교차 타입까지, 다양한 타입 시스템을 이해함으로써 더욱 안전하고 안정적인 코드를 작성할 수 있을 것 같다.