천진난만 코딩 스토리

2023.06.17) 타입스크립트의 클래스 & 인터페이스 (2) 본문

TIL(Today I Learned)

2023.06.17) 타입스크립트의 클래스 & 인터페이스 (2)

Wisdom_1104 2023. 6. 17. 21:22

1. Type

type 의 특징을 몇 가지 짚어보자면,

// 1, 2
type Health = number;
// 3
type Team = "red" | "blue" | "yellow";

type Player = { nickname: string; team: Team; health: Health };

const rhino: Player = {
  nickname: "ori",
  team: "blue",
  health: 1,
};
  1. 특정 값이나 객체의 값에 대한 타입을 지정해줄 수 있다.
  2. Type alias를 만들어줄 수 있다.
  3. 타입을 특정한 값을 가지도록 제한할 수 있다.

 

2. Interface

type과 비슷한 것이 있는데, 바로 interface 이다.

오브젝트 모양을 타입스크립트에게 설명해 주기 위한 키워드이다.

즉, type보다 활용도는 떨어지지만 간단하게 나타낼 때 좋다.

//type
type Player = {
  nickname: string;
  team: Team;
  health: Health;
}
//interface
interface Player {
  nickname: string;
  team: Team;
  health: Health;
}

위 두개는 같다. 객체의 타입 설정에 유용하게 쓰일 수 있다.

interface의 또 다른 특징으로는 속성들을 '축적'시킬 수 있다는 것이다.

interface User {
  name: string;
}
interface User {
  lastName: string;
}
interface User {
  health: number;
}
const ori: User = { name: "ori", lastName: "p", health: 5 };

 

3. Type과 Interface 차이점

1) 타입을 특정한 값이나 alias 자체를 interface가 설정하지 못한다.

① type

// O
type Team = "red" | "blue" | "yellow";
type Mumber = number;

② interface

// X
interface Team = "red" | "blue" | "yellow";
interface Mumber = string;

 

2) 상속받는 문법 및 중복 사용

① type

type A = {
  firstName: string;
};

type AA = A & {
  lastName: string;
};

// 불가능
// 이미 선언되어서 중복이 안됨
type AA = {
  age: number;
};

 interface

interface B {
  firstName: string;
}
interface BB extends B {
  lastName: string;
}
// 가능
interface BB {
  age: number;
}
// 가능
interface B {
  lastName: string;
  age: number;
}

 

4. Interface 사용

1) 객체 지향과 비슷한 문법을 사용해 extends로 상속받을 수 있다.

interface User {
  name: string;
  readonly age: number; //읽기 전용
}
interface Player extends User {}

const Olaf: Player = {
  name: "Olaf",
  age: 5,
};
Olaf.age = 7; // X, 읽기 전용 속성이므로 'age'에 할당할 수 없습니다.

 

2)  추상 클래스를 Interface와 접목 가능하다.

abstract class User {
  constructor(
    protected firstName: string, 
    protected lastName: string
  ) {}
  abstract sayHi(name: string): string;
  abstract fullName(): string;
}
class Player extends User {
  fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
  sayHi(name: string) {
    return `Hello ${name}. My name is ${this.fullName()}`;
  }
}

위의 코드에서 User를 직접적으로 만지지않고, 상속받고 파생되는 클래스와 인스턴스로 사용할건데,

JS 컴파일 되도 남아있다. 이를 없애고 싶다면?

Interface를 사용하여 JS로 컴파일 시 사라지고, 클래스보다 훨씬 가벼우면서 교체가능하도록 한다.

 

interface User {
  firstName: string;
  lastName: string;
  sayHi(name: string): string;
  fullName(): string;
}
class Player implements User {
  constructor(
    public firstName: string, 
    public lastName: string
  ) { }
  fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
  sayHi(name: string) {
    return `Hello ${name}. My name is ${this.fullName()}`;
  }
}
  • 추상클래스는 interface로 바꾼다.
  • implements 키워드를 써서 User를 구현해야하는(추상클래스 상속) Player 클래스 생성한다.
  • 추상클래스에 썼던 생성자를 작성한다.
    (보호레벨을 public으로 받는다. 인터페이스를 상속받을 땐 다른 레벨이 아닌 public로만 받아야한다)
  • 구현한 메소드도 그대로 작성한다.
  • 2개 이상의 인터페이스를 상속받을 수 있다.

 

3) 함수형에서 사용

// 파라미터에 User 적용
function makeUser(user: User) {
  return "Hello!";
}

// return까지 User 타입으로
function makeUserReturn(user: User): User {
  return { 
  	firstName: "Ol", 
    lastName: "af", 
    fullName: () => "Xx", sayHi: (name) => "string"
  };
}
makeUser({ 
	firstName: "Ol", 
    lastName: "af", 
    fullName: () => "Xx", sayHi: (name) => "string" 
});