📑 목차
이번에는 타입스크립트에서 객체(Object) 의 타입을 정의하는 방법과 구조적 타입 시스템, 그리고 선택적/읽기 전용 프로퍼티 같은 특수 문법에 대해 알아본다.
1. object 타입
타입스크립트에서 객체의 타입을 정의하는 가장 간단한 방법은 object 키워드를 사용하는 것이다.
let user: object = {
id: 1,
name: "탬니",
};
하지만 이렇게 object로 타입을 정의하면 한 가지 치명적인 문제가 발생한다.
// user.id; // ❌ 에러 발생 (Property 'id' does not exist on type 'object')
왜 에러가 날까?object 타입은 해당 변수가 '객체이다' 라는 사실만 알려줄 뿐, 그 객체 안에 어떤 프로퍼티가 있는지에 대한 정보는 전혀 없기 때문이다. 따라서 실제 프로퍼티에 접근하려고 하면 에러가 발생한다.
우리가 원하는 것은 객체의 구체적인 구조까지 타입으로 정의하는 것이다. 이때 사용하는 것이 바로 객체 리터럴 타입이다.
2. 객체 리터럴 타입
객체 리터럴 타입은 중괄호 {}를 열고, 객체가 가져야 할 프로퍼티의 이름과 타입을 직접 나열하여 정의한다.
let user: {
id: number;
name: string;
} = {
id: 1,
name: "탬니",
};
console.log(user.id); // 1 (정상 작동)
이제 타입스크립트는 user 객체 안에 id가 숫자형이고, name이 문자열이라는 것을 정확히 인지한다. 점 표기법을 사용할 때 자동 완성이 지원되고, 타입 검사도 수행된다.
구조적 타입 시스템 (Structural Type System)
여기서 알 수 있는 중요한 사실은, 타입스크립트가 프로퍼티를 기준으로 객체의 타입을 정의한다는 점이다.
- 명목적 타입 시스템 (Nominal Type System): C#, Java처럼 클래스나 인터페이스의 '이름'을 기준으로 타입을 따지는 방식.
- 구조적 타입 시스템 (Structural Type System): 타입스크립트처럼 이름이 무엇이든 "어떤 구조(프로퍼티)를 가지고 있느냐" 를 기준으로 타입을 따지는 방식.
마치 "이름(name)과 색깔(color)이 있으면 그건 강아지 객체야"라고 판단하는 것과 같다. 이를 프로퍼티 베이스드 타입 시스템(Property-based Type System) 이라고도 부른다.
let dog: {
name: string;
color: string;
} = {
name: "뽀삐",
color: "white",
};
3. 특수한 프로퍼티 정의하기
객체 타입을 정의할 때 상황에 따라 프로퍼티를 선택적으로 만들거나, 수정할 수 없게 만들 수 있다.
3-1. 선택적 프로퍼티 (Optional Property)
객체를 다루다 보면 특정 프로퍼티가 있을 수도 있고 없을 수도 있는 경우가 있다. 예를 들어 이름은 있지만 id는 아직 발급되지 않은 유저가 있을 수 있다.
이때 프로퍼티 이름 뒤에 물음표(?) 를 붙여주면 된다.
let user: {
id?: number; // 있어도 되고 없어도 됨
name: string;
} = {
id: 1,
name: "탬니",
};
// id가 없는 객체를 할당해도 에러가 나지 않음
user = {
name: "홍길동",
};
주의할 점: 선택적 프로퍼티라 하더라도, 만약 값이 존재한다면 반드시 정의된 타입(number)이어야 한다. 엉뚱한 타입(string 등)을 넣으면 에러가 발생한다.
3-2. 읽기 전용 프로퍼티 (Readonly Property)
API 키나 고유 ID처럼, 객체 생성 시 한 번 값이 정해지면 절대 바뀌면 안 되는 값들이 있다.
이때는 프로퍼티 이름 앞에 readonly 키워드를 붙인다.
let config: {
readonly apiKey: string; // 읽기 전용
} = {
apiKey: "my-secret-key",
};
// config.apiKey = "hacked"; // ❌ 에러 발생 (읽기 전용 속성이므로 할당 불가)
readonly를 사용하면 의도치 않게 중요한 데이터가 수정되는 것을 코드 레벨에서 방지할 수 있다.
요약
- object 타입: 단순히 "객체임"만 명시하므로 프로퍼티 접근이 불가능하다. 지양하는 것이 좋다.
- 객체 리터럴 타입:
{ key: type }형태로 구조를 명확히 정의한다. (구조적 타이핑) - 선택적 프로퍼티 (
?): 해당 프로퍼티가 없어도 에러가 나지 않는다. - 읽기 전용 프로퍼티 (
readonly): 초기화 이후 값을 수정할 수 없다.
