Notice
Recent Posts
Recent Comments
Link
관리 메뉴

윤일무이

[TypeScript] 인터페이스 본문

❔ TypeScript/💭 한 입 크기 TypeScript

[TypeScript] 인터페이스

썸머몽 2023. 12. 20. 01:16
728x90

인터페이스

// 인터페이스
interface Person {
  name: string;
  age: number;
}

const person: Person = {
  name: "이정환",
  age : 27
};
  • 타입 별칭처럼 타입의 이름을 지어주는 문법으로 상호간에 약속된 규칙
  • 상속, 합침 등의 특수한 기능을 제공해 객체의 구조를 정의하는 데 더 특화된 문법
interface Person {
  readonly name: string;
  age?: number;
}

const person: Person = {
  name: "summermong",
  // age: 27,
};

person.name = 'wintermong' // 읽기 전용으로 수정 불가
  • 선택적 프로퍼티 설정도 동일하게 사용 가능하다.
  • 읽기 전용 키워드인 readonly로 수정을 불가하게 할 수도 있다.
interface Person {
  readonly name: string;
  age?: number;
  sayHi: () => void; // sayHi(): void; 와 같이 호출 시그니처 사용 가능
}
  • 함수 타입 표현식으로 sayHi 메서드의 타입을 정의했다.
  • 호출 시그니처를 사용해서 메서드의 타입을 정의할 수도 있다.
// 함수 타입 표현식으로 메서드 타입 정의 시 오버로딩 구현 불가
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;
}
  • sayHi 메서드 타입을 정의할 때 함수 타입 표현식으로 하면 중복된다고 이해, 오버로딩 구현이 불가하다.
  • 이 때 호출 시그니처로 정의하면 오버로딩 구현이 가능하다.
type Type1 = number | string;
type Type2 = number & string;

interface Person {
  name: string;
  age: number;
} | number // ❌
  • 인터페이스는 타입 별칭과 대부분 비슷하게 동작하지만, 유니온이나 인터섹션 타입을 정의할 수 없다. 
type Type1 = number | string | Person;
type Type2 = number & string & Person;

const person: Person & string = {
  name: "summermong",
  age: 27,
};
  • 인터페이스로 만든 타입을 유니온, 인터섹션으로 이용해야 한다면 타입 별칭과 사용하거나 타입 주석에 직접 기입해야 한다.

인터페이스 확장 (상속)

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 타입의 프로퍼티 1개가 변경되면 다 변경해야 해서 유지보수가 어렵다.
  • 이렇게 특정 인터페이스를 기반으로 여러 개의 인터페이스가 파생되는 경우 확장 기능을 사용한다.
interface Animal {
  name: string;
  color: string;
}

interface Dog extends Animal {
  breed: string;
}

interface Cat extends Animal {
  isScratch: boolean;
}

interface Chicken extends Animal {
  isFly: boolean;
}
  • extends 뒤에 확장할 타입의 이름을 정의하면 해당 타입에 정의된 모든 프로퍼티를 다 가지고 오게 된다.
interface Animal {
  name: string;
  color: string;
}

interface Dog extends Animal {
  isBark: boolean;
}

const dog: Dog = {
  name: '',
  color: '',
  isBark: true,
};
  • Animal 타입이 있고 Animal 타입을 상속 받은 Dog 타입이 있다.
  • 객체 dog의 타입이 Dog 타입이라면 Animal은 Dog 타입의 슈퍼 타입이 된다.
interface Animal {
  name: string;
  color: string;
}

interface Dog extends Animal {
  // name: '주몽' // 에러 발생
  isBark: boolean;
}

const dog: Dog = {
  name: '',
  color: '',
  isBark: true,
};
  • Animal 타입의 name이 string이고, 여기서 확장된 Dog 타입의 name이 string 리터럴이면 에러가 발생한다.
  • 프로퍼티를 재정의 할 때, 원본 타입을 A, 재정의된 타입을 B라고 할 때 반드시 A가 B의 슈퍼 타입이 되도록 해야 한다.
type Animal = {
  name: string;
  color: string;
};

interface Dog extends Animal {
  breed: string;
}
  • 추가로 인터페이스는 같은 인터페이스끼리 뿐만 아니라 타입 별칭으로 정의된 객체도 확장할 수 있다.
interface DogCat extends Dog, Cat {}

const dogCat: DogCat = {
  name: "",
  color: "",
  breed: "",
  isScratch: true,
};
  • 또 하나의 인터페이스만 확장할 수 있는 게 아니라 여러 개의 인터페이스를 확장하는 것도 가능하다.

인터페이스 선언 합침 (declaration merging)

interface Person {
  name: string;
}

interface Person {
  age: number;
}

const person: Person = {
  name: '',
  age: 27,
};
  • 타입 별칭은 동일한 스코프 내에 중복된 이름으로 선언할 수 없지만, 인터페이스는 가능하다.
  • 그 이유는 중복된 이름의 인터페이스 선언은 하나로 합쳐지기 때문이다.
  • 이렇게 동명의 인터페이스가 합쳐지는 것을 선언 합침이라고 부른다.
interface Person {
  name: string;
}

interface Person {
  name: number;
  age: number;
}
  • 단, 이런 선언 합침은 프로퍼티의 타입이 반드시 같아야 한다. (서브 타입도 불가)
  • 이렇게 동일한 프로퍼티의 타입을 다르게 정의한 상황을 충돌이라고 하며, 선언 합침에서 이러한 충돌은 허용되지 않는다.

 **출처: 한 입 크기로 잘라먹는 타입스크립트 (인프런, 이정환 강사님) 

728x90