타입스크립트를 사용하면서 타입을 정의할 때 interface
또는 type
을 사용할 수 있습니다.
두 개 차이가 뭔지 항상 궁금하긴 했지만 극강의 귀차니즘으로 인해 애써 흐린눈하며.. 그저 글자수가 더 적은 type 만을 고집해왔는데요. .ㅎ
이제는 더이상 물러날 수가 없겠다는 생각이 들어 이 둘의 차이에 대해 공부해보았습니다 !
user
라는 객체에 어떤 속성이 들어가고, 해당 value의 타입은 무엇인지를 구체적으로 정의해줍니다.
interface User {
name: string;
age: number;
isAdmin: boolean;
}
const user: User = {
name: "Alice",
age: 25,
isAdmin: true,
};
함수의 파라미터 타입을 명시할 수 있습니다.
아래코드에서는 매개변수로 받는 product
의 타입을 명시합니다.
예를들어 product인데 user 정보를 넘겨줄 경우 오류가 나겠죠!
interface Product {
name: string;
price: number;
inStock: boolean;
}
function printProductDetails(product: Product): void {
console.log(`${product.name} costs $${product.price} and is ${product.inStock ? "in stock" : "out of stock"}`);
}
printProductDetails({ name: "Laptop", price: 999.99, inStock: true });
함수의 형태를 정의합니다.
아래 코드는 greet
라는 무엇을 매개로 받고, 무엇을 반환하는지 나타냅니다.
interface Greet {
(name: string): string;
}
const greet: Greet = (name) => {
return `Hello, ${name}!`;
};
console.log(greet("Alice")); // "Hello, Alice!"
특정 클래스가 반드시 정의해야 할 속성과 메서드를 강제할 수 있습니다. 이때 implements
라는 키워드를 사용합니다.
아마 JAVA를 공부하셨던 분이라면 익숙하실거예요
interface Animal {
name: string;
makeSound(): void;
}
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound() {
console.log("Woof!");
}
}
const myDog = new Dog("Buddy");
myDog.makeSound(); // "Woof!"
인터페이스는 다른 인터페이스를 확장하여 더 복잡한 구조를 정의할 수 있습니다.
type
과의 가장 큰 차이점이라고도 할 수 있을 것같아요.
interface Person {
name: string;
age: number;
}
interface Employee extends Person {
employeeId: number;
role: string;
}
const employee: Employee = {
name: "John",
age: 30,
employeeId: 123,
role: "Developer",
};
인터페이스를 확장해서 쓸 생각은 한번도 해보지 못했는데, 인터페이스를 확장한다면 조금 더 가독성이 높아지고, 중복코드를 방지할 수 있을것같다는 생각이 들었습니다.
예를들어 User Type
, UserJoinType
, UserProfileType
을 사용한다고 했을 때,
interface UserType {
name: string;
phone: string;
}
interface UserJoinType extends UserType {
password: string;
confirmPassword: string;
verifiedNumber: number;
}
interface UserProfileType extends UserType {
profilePicture: string;
bio: string;
address: string;
joinedDate: Date;
}
이렇게 타입을 선언하는 과정에서 겹치는 부분은 굳이 다시 쓰지 않아도 된다는 장점이 있습니다.
const user: UserType = {
name: "Alice",
phone: "123-456-7890",
};
const userJoin: UserJoinType = {
name: "Alice",
phone: "123-456-7890",
password: "password123",
confirmPassword: "password123",
verifiedNumber: 1234,
};
const userProfile: UserProfileType = {
name: "Alice",
phone: "123-456-7890",
profilePicture: "https://example.com/profile.jpg",
bio: "Hello, I'm Alice! I love coding and hiking.",
address: "123 Maple St, Somewhere, Earth",
joinedDate: new Date("2023-01-15"),
};
type 이라는 이름에서 알 수 있듯이, 타입을 정의할 때 사용하는 키워드입니다.
type 별칭을 만들어서 여러 상황에서 유연하게 활용할 수 있다는 것이 가장 큰 특징입니다.
interface 보다는 조금 더 좁은 개념으로 받아들일 수 있을것같아요.
기본적인 자료형 string
, number
에도 ID 라는 별칭을 만들어서 사용할 수 있습니다.
매번 string ,number 를 넣어주는 것보다 가독성도 높아지고, 일관성을 유지할 수 있겠죠.
type ID = string | number;
let userId: ID = "12345";
let orderId: ID = 67890;
객체 구조를 type
으로 정의하여 반복적으로 사용할 수 있습니다.
동일한 구조의 객체를 여러번 사용할 경우 유용합니다 .
type Product = {
name: string;
price: number;
inStock: boolean;
};
const apple: Product = {
name: "Apple",
price: 1.5,
inStock: true,
};
interface 와 가장 큰 차이점이라고 생각하는 부분입니다.
type
을 사용하면 다양한 타입을 유니온 타입으로 정의할 수 있습니다.
type ButtonSize = "small" | "medium" | "large";
type ButtonColor = "primary" | "secondary" | "danger";
function createButton(size: ButtonSize, color: ButtonColor) {
console.log(`Creating a ${size} button with ${color} color.`);
}
createButton("medium", "primary");
interface
의 확장과 비슷하게 &
를 사용하여 교차 타입을 만들 수 있습니다.
type Person = {
name: string;
age: number;
};
type Contact = {
phone: string;
email: string;
};
type Employee = Person & Contact;
const employee: Employee = {
name: "Alice",
age: 30,
phone: "123-456-7890",
email: "alice@example.com",
};
이 두가지의 차이를 간단하게 정리하면 다음과 같습니다.
Interface는 선언 병합을 통해 여러 번 확장이 가능합니다. 같은 이름의 인터페이스를 여러 곳에서 선언하면 자동으로 병합되어 하나의 구조로 만들어집니다.
Type은 확장 불가이며, 선언 병합을 지원하지 않습니다. 이미 선언된 타입을 다시 선언할 수 없고, 확장을 위해서는 유니온 타입 또는 & 연산자를 사용합니다.
Interface는 객체의 구조를 주로 정의할 때 사용하며, 클래스의 구현 타입으로도 많이 사용됩니다.
Type은 기본 자료형(문자열, 숫자 등)에 대한 타입별칭을 정의하거나, 유니온 타입, 튜플 등으로도 정의가 가능합니다.
Interface는 유니온 타입을 지원하지 않아, 특정 구조의 객체를 위한 타입만 정의할 수 있습니다.
Type |
연산자를 사용해 유니온 타입을 정의할 수 있습니다. 예를 들어, type Shape = Circle | Square;
처럼 다양한 구조를 합쳐 하나의 타입으로 정의할 수 있습니다.
이렇게 직접 interface 와 type의 차이점을 공부하다보니 지금 하고있는 프로젝트에서 어떤 부분을 수정해야 할지 감이 오는것같습니다.
지금까지는 type 으로만 주구장창 정의했었는데, 몇개는 interface 로 변경을 해서 중복되는 부분을 줄이고, 비슷한 성질을 가진 것끼리 잘 묶여지도록 수정할 수 있을것같네요. 이렇게 수정한다면 아예 제 코드를 처음보는 사람이 유지보수를 하게 될 때에도 조금 더 편하고 빠르게 파악할 수 있을것같습니다.
복잡하지 않은 서비스에서는 interface 를 쓰든, type을 쓰든 성능이나 가독성이나 크게 문제가 될 건 없겠지만 지금부터라도 이렇게 어떤 상황에서 무엇을 사용하는 것이 더 적절한건지 파악하고, 의도를 가지고 골라 사용하는 습관을 가지게 된다면 더 좋은 개발자가 될 수 있을것같습니다.
무엇이든지 '그냥' 하는 것이 아니라 '의도를 가지고'하는 것이 중요하니까요 !