Frontend/TypeScript

[TypeScript] 4. 인터페이스

ayeongjin 2025. 1. 26. 00:03

인터페이스

타입 별칭과 동일하게 타입에 이름을 지어주는 또 다른 문법

interface Person {
  name: string;
  age: number;
}
  • 이렇게 정의한 인터페이스를 타입 주석과 함께 사용해 변수의 타입을 정의할 수 있다.
const person: Person = {
  name: "이정환",
  age : 27
};
  • 이렇듯 인터페이스는 타입 별칭과 문법만 조금 다를 뿐 기본적인 기능은 거의 같다고 볼 수 있다.

 

1. 선택적 프로퍼티

인터페이스에서도 동일한 방법으로 선택적 프로퍼티 설정이 가능하다.

interface Person {
  name: string;
  age?: number;
}

const person: Person = {
  name: "이정환",
  // age: 27,
};

 

2. 읽기 전용 프로퍼티

읽기 전용 프로퍼티 또한 동일한 방법으로 설정 가능

interface Person {
  readonly name: string;
  age?: number;
}

const person: Person = {
  name: "이정환",
  // age: 27,
};

person.name = '홍길동' // ❌

 

3. 메서드 타입 정의하기

메서드의 타입을 정의하는 것 또한 가능

  • 함수 타입 표현식을 이용해 sayHi 메서드의 타입을 정의
interface Person {
  readonly name: string;
  age?: number;
  sayHi: () => void;;
}
  • 함수 타입 표현식 말고 다음과 같이 호출 시그니쳐를 이용해 메서드의 타입을 정의할 수도 있다.
interface Person {
  readonly name: string;
  age?: number;
  sayHi(): void;
}

 

4. 메서드 오버로딩

  • 함수 타입 표현식으로 메서드의 타입을 정의하면 메서드의 오버로딩 구현이 불가능
interface Person {
  readonly name: string;
  age?: number;
  sayHi: () => void;
  sayHi: (a: number, b: number) => void; // ❌
}
  • 호출 시그니처를 이용해 메서드의 타입을 정의하면 오버로딩 구현이 가능
interface Person {
  readonly name: string;
  age?: number;
  sayHi(): void;
  sayHi(a: number): void;
  sayHi(a: number, b: number): void;
}

 

5. 하이브리드 타입

인터페이스또한 함수이자 일반 객체인 하이브리드 타입을 정의할 수 있다

interface Func2 {
  (a: number): string;
  b: boolean;
}

const func: Func2 = (a) => "hello";
func.b = true;

 

1) 주의할 점 1

  • 인터페이스는 대부분의 상황에 타입 별칭과 동일하게 동작하지만 몇가지 차이점이 존재한다.
  • 타입 별칭에서는 다음과 같이 Union이나 Intersection 타입을 정의할 수 있었던 반면 인터페이스에서는 할 수 없음
type Type1 = number | string;
type Type2 = number & string;

interface Person {
  name: string;
  age: number;
} | number // ❌
  • 따라서 인터페이스로 만든 타입을 Union 또는 Intersection으로 이용해야 한다면 다음과 같이 타입 별칭과 함께 사용하거나 타입 주석에서 직접 사용해야 함
type Type1 = number | string | Person;
type Type2 = number & string & Person;

const person: Person & string = {
  name: "이정환",
  age: 27,
};

 


 

인터페이스 확장

인터페이스 확장이란 하나의 인터페이스를 다른 인터페이스들이 상속받아 중복된 프로퍼티를 정의하지 않도록 도와주는 문법

 

1. 인터페이스 확장하기

// 인터페이스 확장 전

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

interface Dog {
  name: string;
  age: number;
  isBark: boolean;
}

interface Cat {
  name: string;
  age: number;
  isScratch: boolean;
}

interface Chicken {
  name: string;
  age: number;
  isFly: boolean;
}
  • Animal 타입을 기반으로 Dog, Cat, Chicken이 각각의 추가적인 프로퍼티를 갖고 있는 형태
  • 추가로 name 그리고 age 프로퍼티가 모든 타입에 중복해서 정의
interface Animal {
  name: string;
  color: string;
}

interface Dog extends Animal {
  breed: string;
}

interface Cat extends Animal {
  isScratch: boolean;
}

interface Chicken extends Animal {
  isFly: boolean;
}

const dog: Dog = {
  name: "돌돌이",
  color: "brown",
  breed: "진도",
};
  • interface 타입이름 extends 확장_할_타입이름 형태로 extends 뒤에 확장할 타입의 이름을 정의
  • → 해당 타입에 정의된 모든 프로퍼티를 다 가지고 온다.
  • 따라서 Dog, Cat, Chicken 타입은 모두 Animal 타입을 확장하는 타입이기 때문에 name, age 프로퍼티를 갖게 된다.
  • 이때 확장 대상 타입인 Animal은 Dog 타입의 슈퍼타입이 됩니다.

 

2. 프로퍼티 재정의하기

  • 다음과 같이 확장과 동시에 프로퍼티의 타입을 재 정의 하는 것 또한 가능
interface Animal {
  name: string;
  color: string;
}

interface Dog extends Animal {
  name: "doldol"; // 타입 재 정의
  breed: string;
}
  • Dog 타입은 Animal 타입을 확장하며 동시에 name 프로퍼티의 타입을 String 타입에서 “doldol” String Literal 타입으로 재정의 가능
  • 프로퍼티를 재정의할 때 원본 타입을 A 재정의된 타입을 B라고 하면 반드시 A가 B의 슈퍼 타입이 되도록 재정의 해야 합니다.

 

3. 타입 별칭을 확장하기

인터페이스는 인터페이스 뿐만 아니라 타입 별칭으로 정의된 객체도 확장 가능

type Animal = {
  name: string;
  color: string;
};

interface Dog extends Animal {
  breed: string;
}

 

4. 다중 확장

또 여러개의 인터페이스를 확장하는 것 또한 가능

interface DogCat extends Dog, Cat {}

const dogCat: DogCat = {
  name: "",
  color: "",
  breed: "",
  isScratch: true,
};

 


 

인터페이스 선언 합치기

 

1. 선언 합침

타입 별칭은 동일한 스코프 내에 중복된 이름으로 선언할 수 없는 반면 인터페이스는 가능

// 타입 별칭

type Person = {
  name: string;
};

type Person = { ❌
  age: number;
};
// 인터페이스

interface Person {
  name: string;
}

interface Person { // ✅
  age: number;
}
  • 중복된 이름의 인터페이스 선언은 결국 모두 하나로 합쳐지기 때문입니다.
  • 따라서 위 코드에 선언한 Person 인터페이스들을 결국 합쳐져 다음과 같은 인터페이스가 된다.
interface Person {
	name: string;
	age: number;
}
  • 이렇게 동일한 이름의 인터페이스들이 합쳐지는 것을 선언 합침(Declaration Merging)이라고 부른다.
// 사용 예시

interface Person {
  name: string;
}

interface Person {
  age: number;
}

const person: Person = {
  name: "이정환",
  age: 27,
};

 

2. 주의할 점

동일한 이름의 인터페이스들이 동일한 이름의 프로퍼티를 서로 다른 타입으로 정의한다면 오류 발생

interface Person {
  name: string;
}

interface Person {
  name: number; // 오류 : 충돌 ! !
  age: number;
}
  • 첫번째 Person에서는 name 프로퍼티의 타입을 string 으로 두번째 Person 에서는 name 프로퍼티의 타입을 number 타입으로 정의
  • 이렇게 동일한 프로퍼티의 타입을 다르게 정의한 상황을 ‘충돌’ 이라고 표현하며 선언 합침에서 이런 충돌은 허용되지 않음