본문 바로가기
Study-Note/TypeScript

[Type Script] 객체, Union, enum, Type alias, interface

by Ji-u 2025. 1. 13.

 

안녕하세요! 

TypeScript의 개념과 기본 타입 다음으로 객체 타입과 Union, Type alias(타입 별칭), interface에 대해 정리해보고자 합니다.

리터럴 타입과 type과 interface를 언제 사용하면 좋을지도 함께 작성해보고자 합니다. 

 

 

📎 객체 타입

객체는 key와 value를 가지는 데이터구조로 타입을 정의할 때에는 {key: Type} 을 작성해줍니다. 해당 key가 가리키는 값에는 정의된 타입의 데이터를 담을 수 있습니다. 옵셔널 프로퍼티일 경우 프로퍼티 이름 뒤에 ?를 붙이면 됩니다. 

function setPosition(pt: {x:number; y:number}) {}

function setName(obj: {first:string; last?:string;}) {}

 

 

📎 유니온 타입(Union)

타입 스크립트에서는 연산자를 사용하여 새로운 타입을 만들 수 있습니다. 유니온 타입은 서로 다른 두개 이상의 타입을 조합하여 사용하는 것으로, 정의된 타입 중 하나를 타입으로 가질 수 있습니다. 조합에 사용된 각 타입을 유니언 타입의 멤버라고 부릅니다

function printId(id: number | string) {}

 

유니온 타입을 사용할 때에는 하나의 타입으로 명시되지 않기 때문에 내부 코드에서는 분기를 타야하는 경우가 있을 수 있습니다. 예로 string메서드를 사용하기 위해선 입력된 매개변수의 값이 string 타입인지 체크한 후 사용할 수 있습니다. typeof 키워드를 이용해서 확인할 수 있습니다.

 

function printId(id: number | string) {
  console.log(id.toUpperCase()); // Property 'toUpperCase' does not exist on type 'string | number'.

	if (typeof id === "string") {
	    // 이 분기에서 id는 'string' 타입을 가집니다
    	console.log(id.toUpperCase());
	} else {
    	// 여기에서 id는 'number' 타입을 가집니다
	    console.log(id);
    }
}

 

유니온 타입의 장점으로 하나로 편집기에서 드롭다운으로 자동 선택이 가능하게 됩니다. 함수를 호출하는 곳에서 어떤 입력값을 넣을 수 있는지 자동완성 기능을 이용할 수 있기 때문에 효율적인 개발이 가능합니다. 또안 유니온 멤버가 아닌 값을 입력하게 되면(예를 들어 'top') 편집기에서는 해당 인수는 할당할 수 없다는 메세지를 안내받게 됩니다.

 

 

📎 Enum

typeScript에서는 enum 타입도 사용할 수 있습니다.

0~ 숫자값으로 할당되며, 기본 시작값을 줄 수 있습니다. 또한 값 자체를 할당할 수도 있습니다.

enum Direction {
	Up = 1,
	Down,
	Left,
	Right,
}

Direction.Up // 1
Direction.Down // 2
Direction.Left // 3
Direction.Right // 4

 

먼저 숫자형을 살펴보자면 위와 같이 사용할 수 있습니다. 위 예시는 1로 기본 시작값을 줌으로써 1,2,3,4의 값을 가지게 됩니다. 기본값을 주지 않을 경우 0 부터 증가되는 값이 할당되게 됩니다. enum 숫자형의 경우 해당 숫자를 입력할 때도 에러가 없이 사용 가능하기 때문에 명시적인 안내를 주지는 못합니다. 

 

enum Direction {
	Up,
	Down,
	Left,
	Right,
}
  
  
  function setPosition(value: Direction) {} 
  
  setPosition(1) // 가능!

 

아래와 같이 enum에 문자열 값을 할당한 문자열 enum을 이용하거나 Union 타입을 이용하면 편집기의 피드백을 받을 수 있기 때문에 더 안전한 개발을 할 수 있습니다.

 


 

📎 Type Alias 

객체 타입과 유니온 타입을 재사용 하거나 어떤 타입의 객체 이름을 붙혀줄 수 있습니다. Type Alias를 이용해 새로운 타입을 정의할 수 있습니다. 예를 들어 아까 객체 타입에서 사용한 코드에 타입 별칭을 붙힌다면 아래와 같이 의도를 전달할 수 있으며, 문서화 효과를 볼 수 있습니다.

type Point = {
	x: number;
	y: number;
}
function setPosition(pt: Point) {
	console.log(pt.x, pt.y);
}

type Name = {
	first: string;
	last?: string;
}
function setName(name: Name) {}


type ID = number | string;

function printId(id: ID) {}

 

 

Type alias를 유용하게 사용하는 케이스 중 하나로 상태가 있습니다. 유저 상태, 로그인 상태 등등 프론트엔드 코드에서 상태에 따라 다른 UI를 보여주도록 분기타는 경우가 있는데, 이때 각 State의 타입을 만들어서 작성할 수 있습니다.

 

type SuccessState = {
	result: 'success',
	message: string,
}
type FailState = {
	result: 'fail',
	reason: string;
    retry: boolean,
};
type ToastState = SuccessState | FailState; 

function showToastMessage(state: ToastState) {
	if (state.result == 'success') {
		// 성공 시 메세지를 보여준다
	} else {
		// 실패 시 이유와 재시도 여부를 보여준다
	}
}

 

Type 의 객체 구조가 다를 때 동일한 프로퍼티를 추가해서 분기를 타는 방법으로 작성하면 코드를 좀 더 간결하게 작성할 수 있습니다.

추가로 Type Alias는 확장성이 뛰어납니다. type을 & 키워드를 이용해 합치고, 프로퍼티를 다른 별칭으로 선언하는 등 재구성할 수 있습니다.

 

type UserInfo = {
	id: number;
	name: string;
    age: number;
    gender: 'male' | 'female';
    address?: string
}

// 별도로 관리하지 않음으로써 수정 시 신경 써야하는 영역이 줄고 연관된 데이터의 결합도를 높혀줍니다.
type UserId = UserInfo['id']
type Gender = UserInfo['gender'] 


// Omit은 2번째 인자값을 제외하고, Pick은 2번째 인자값들만 꺼내 포함하게 됩니다.
type UserFormWithOmit = Omit<UserInfo, 'id'>;
type UserFormWithPick = Pick<UserInfo, 'name' | 'age' | 'gender' | 'address'>;

// & 를 이용해 합칠 수 있고 교집합됩니다.

type Book = {
	title: string,
	author: string,
}
type BookMetadata = {
	author: string,
    price: number,
}

type BookInfo = Book & BookMetadata;

 

객체와 마찬가지로 타입에서 index의 키값을 이용해 해당 타입을 꺼내올 수 있습니다. 

위의 예제에서는 UserId, Gender 타입에 해당하며 동일한 타입을 바라보게 되고, 수정할 때 UserInfo만 수정하면 됩니다.

또한 Type Script 에서는 제공되는 유틸 타입을 이용해서 제외하거나, 추가하거나, 옵셔널로 변경하는 등의 작업을 할 수 있습니다.

Omit의 경우 타입에서 전달받은 인자값을 제외하고 반환하게 됩니다. 

Pick의 경우 전달받은 인자값을 포함하고 반환하게 됩니다.

 

 

type Notice = {
	id: number,
	title: string,
	description: string,
	thumbnail: {
		url: string,
		alt: string
	}
}

type NoticeReadOnly = Readonly<Notice>;
type NoticeOptional = Partial<Notice>;

 

 

 

TypeScript에서 제공하는 유틸타입을 통해 재구성도 가능합니다. 상세 페이지에서는 readonly 타입을 사용함으로써 추후 수정 시 리드온리 상태를 유지해야한다는 것을 명시할 수 있습니다. (좀 더 자세한 원리는 제네릭 편에서 함께 진행하겠습니다 :) )

 

 

 


 

📎  Interface

interface는 Typa alias와 유사하게 정의합니다. 객체의 구조를 정의하는게 사용되며 속성의 키와 타입, 옵셔널 여부 등을 명시할 수 있습니다. 변수, 함수, 클래스의 타입을 정의할 때 사용할 수 있습니다. 

 

interface User {
	name: string;
	age: number
}

const user1: User = { name: "miffy", age: 70 }

 

인터페이스는 클래스와 동일하게 extends 키워드를 이용해서 상속이 가능합니다. 그리고 동일한 인터페이스를 중복으로 선언하게 되면 merge 가 됩니다.  

 

interface Shape {
	color: string;
}

interface Circle extends Shape {
	radius: number;
}

const circle: Circle = { color: "red", radius: 10 };

 

 

 

 

📎 type과 interface의 차이점. 언제 써야할까?

인터페이스와 타입의 차이점을 먼저 살펴보면 아래와 같습니다. 

특징 Interface Type
사용 목적 주로 객체의 구조를 정의하는 데 사용 객체, 기본 타입, 유니언 타입, 튜플 등 다양한 타입을 정의할 수 있음
확장성 다른 인터페이스를 상속하거나 여러 인터페이스를 조합 가능 & 연산자를 사용하여 다른 타입을 결합 가능
유연성 객체의 형태를 명확히 정의하는 데 적합 더 복잡하거나 유연한 타입 정의에 적합
중복 선언 동일한 이름의 인터페이스를 여러 번 선언하면 자동으로 병합됨 동일한 이름의 타입 별칭은 중복 선언 불가능
유니언 및 튜플 지원 지원하지 않음 지원함
컴파일러 출력 Interface는 런타임에 사라짐 Type도 컴파일 시 런타임에서 제거됨

 

// 1. 객체 정의

interface User {
  name: string;
  age: number;
}

type UserType = {
  name: string;
  age: number;
};

// 2. 확장

interface Admin extends User {
  menus: Array<number>;
}

type AdminType = User & {
	menus: Array<number>;
};

// 3. 유니언 타입 = type만 가능
type Result = "success" | "failure";

 

interface는 규격사양에 대한 공유 개념으로 정의해서 사용하곤 합니다. 계약서 처럼 객체 간 혹은 클래스에 대한 문서화로 사용하며, type은 어떤 데이터를 담을지 데이터의 타입을 결정할 때 사용하게 됩니다.

 

[Type Script] 객체, Union, enum, Type alias, interface