TypeScript - 인터페이스 확장

안녕하세요, 미래의 코딩 슈퍼스타 여러분! 오늘 우리는 TypeScript의 인터페이스 세계로 접수하고, 그것들을 확장하는 방법을 배우겠습니다. 이 수업이 끝나면, 프로처럼 강력하고 유연한 인터페이스를 만드는 법을 배우게 될 것입니다. 그러니 마음에 드는 음료를 한 잔 챙기고, 편안하게 자리를 잡아주시고, 우리의 여정을 시작해보겠습니다!

TypeScript - Extending Interfaces

문법

끝없는 이야기에 뛰어들기 전에, 기본적인 내용부터 시작해보겠습니다. TypeScript에서 인터페이스를 확장하는 것은 extends 키워드를 사용하는 것처럼 간단합니다. 일반적인 문법은 다음과 같습니다:

interface ChildInterface extends ParentInterface {
// 추가 속성이나 메서드
}

이를 왕가의 상속에 비유할 수 있습니다. 자식 인터페이스는 부모 인터페이스의 모든 속성과 메서드를 "상속"받아, 자신만의 독특한 기능을 추가할 수 있습니다.

단일 인터페이스 확장

간단한 예제로 시작해보겠습니다. 우리는 마법의 생물에 관한 게임을 만들고 있습니다. 먼저 기본적인 Creature 인터페이스를 정의해보겠습니다:

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

이제 우리는 특별한 종류의 생물 - 용을 만들고 싶습니다! Creature 인터페이스를 확장하여 Dragon 인터페이스를 생성할 수 있습니다:

interface Dragon extends Creature {
breatheFire: () => void;
wingspan: number;
}

이 예제에서 DragonCreaturenameage 속성을 상속받고, 자신만의 breatheFire 메서드와 wingspan 속성을 추가합니다.

이를 어떻게 사용할 수 있는지 보겠습니다:

const smaug: Dragon = {
name: "Smaug",
age: 1000,
wingspan: 200,
breatheFire: () => console.log("Roar! ?")
};

console.log(smaug.name);  // 출력: Smaug
smaug.breatheFire();  // 출력: Roar! ?

이와 같이 smaugCreature의 모든 속성을 가지고 있으며, 추가적인 용 특유의 기능을 가지고 있습니다.

다중 인터페이스 확장

이제 우리의 용이 단순한 생물만이 아니라, 보물을 쌓는 자라면 어떻게 될까요? TypeScript에서는 여러 인터페이스를 확장할 수 있습니다! TreasureKeeper 인터페이스를 만들고 두 개를 확장해보겠습니다:

interface TreasureKeeper {
treasureCount: number;
addTreasure: (item: string) => void;
}

interface DragonLord extends Creature, TreasureKeeper {
breatheFire: () => void;
wingspan: number;
}

이제 우리의 DragonLord는 불을 불고, 보물을 쌓을 수 있는 생물이 되었습니다. 멋지죠?

const falkor: DragonLord = {
name: "Falkor",
age: 500,
wingspan: 150,
treasureCount: 1000,
breatheFire: () => console.log("Whoosh! ?"),
addTreasure: (item) => console.log(`Added ${item} to the hoard!`)
};

falkor.addTreasure("Golden Crown");  // 출력: Added Golden Crown to the hoard!

기존 인터페이스 강화

occasionally, you might want to add more properties to an existing interface. TypeScript allows you to do this by declaring the interface again with the new properties:

interface Creature {
species: string;
}

const unicorn: Creature = {
name: "Sparkles",
age: 100,
species: "Unicorn"
};

이제 Creaturename, age, 그리고 species 속성을 가지고 있습니다. 이 기술은 "선언 통합"이라고 합니다.

복합 인터페이스 생성

기존의 인터페이스를 결합하여 새로운 인터페이스를 만들 수 있습니다. 교차 유형을 사용하여 이를 수행할 수 있습니다:

interface Flyer {
fly: () => void;
}

interface Swimmer {
swim: () => void;
}

type FlyingFish = Flyer & Swimmer;

const nemo: FlyingFish = {
fly: () => console.log("I'm flying! ?✈️"),
swim: () => console.log("Just keep swimming! ?‍♂️")
};

nemo.fly();  // 출력: I'm flying! ?✈️
nemo.swim();  // 출력: Just keep swimming! ?‍♂️

속성과 메서드 오버라이드

인터페이스를 확장할 때 부모 인터페이스의 속성과 메서드를 오버라이드할 수 있습니다. 이는 자식 인터페이스에서 속성이나 메서드를 더 구체화하고 싶을 때 유용합니다:

interface Animal {
makeSound: () => void;
}

interface Cat extends Animal {
makeSound: () => string;  // 더 구체적인 반환 유형
}

const kitty: Cat = {
makeSound: () => "Meow!"
};

console.log(kitty.makeSound());  // 출력: Meow!

이 예제에서 우리는 makeSound 메서드를 void 대신 string으로 반환하도록 오버라이드했습니다.

이제 우리가 다루었던 메서드를 요약하는 표를 보겠습니다:

메서드 설명
단일 인터페이스 확장 extends 키워드를 사용하여 하나의 인터페이스를 상속
다중 인터페이스 확장 extends를 사용하여 쉼표로 구분된 인터페이스 목록을 상속
기존 인터페이스 강화 새로운 속성을 추가하기 위해 인터페이스를 다시 선언
복합 인터페이스 생성 교차 유형(&)을 사용하여 인터페이스를 결합
속성과 메서드 오버라이드 자식 인터페이스에서 속성이나 메서드를 다시 정의

이제 여러분은 TypeScript의 인터페이스 확장 기법을 마스터했습니다. 기억해 두세요, 인터페이스는 레고 블록처럼 - 여러분의 코드에서 복잡하고 유형 안전한 구조를 만드는 데 다양한 방법으로 결합할 수 있습니다.

코딩 여정을 계속하면서, 이 기법들이 더 유연하고 재사용 가능하며 유지보수 가능한 코드를 만드는 데 도움이 될 것을 발견하게 될 것입니다. 그러니 자신감 있게 인터페이스를 사용해보세요! 행복한 코딩 되세요! ??‍??‍?

Credits: Image by storyset