[TS] Chapter 5. Typescript 컴파일러 및 구성-클래스 & 인터페이스_인터페이스

변진상·2023년 5월 31일
0

Typescript 학습

목록 보기
9/13

목표: TS의 인터페이스에 대해 학습한다.

interface란?

interface는 class가 강제적으로 가져야하는 contract이다.

인터페이스는 객체의 구조를 설명하는데 사용한다. 클래스와는 다르게 interface는 객체의 blueprints로 사용되는 것이 아닌 사용자 정의 타입으로 사용한다. 객체의 구조를 타입으로 정의한다.

interface Person {
  // name: string = "Max"; // interface는 initializer를 가질 수 없다는 에러를 띄운다.
  name: string;
  age: number;

  //method도 추가할 수 있다. functionName(parameter1: type): return type;
  greet(phrase: string): void;
}
let user: Person;

user = {
  name: "Jin",
  age: 11,
  greet(phrase) {
    console.log(phrase + this.name);
  },
};

user.greet("안녕하세요 나는 ");

type(사용자 정의 타입)이 아닌 interface를 사용하는 이유

실제로 interface로 구현했던 Person을 type을 이용해 사용자 정의 타입으로 바꿔도 문법적 에러 없이 잘 컴파일, 실행된다.

type Person = {
  name: string;
  age: number;
  greet(phrase: string): void;
}

interface vs type

  • 가장 큰 차이점은 interface는 객체의 구조를 설명하기 위해서만 사용한다.
  • type의 경우 객체의 구조를 설명할 수 있고, union 타입 등을 저장할 수 있다.

그래서 type이 더 유연할 수 있지만, 객체의 구조를 설명할 때는 interface를 사용하는 것이 더 의미적으로 명확하다.

그리고 작업 중 인터페이스를 자주 사용하는 이유는 클래스가 여러 인터페이스를 이행하고 준수하야하는 약속처럼 사용할 수 있기 때문이다.

인터페이스는 구체적인 구현이 아닌 서로 다른 클래스 간의 기능을 공유하기 위해 사용된다. 인터페이스 내에 구현이나 값을 입력하는 것이 아닌 구조와 클래스가 가져야 할 기능을 입력해야한다.

interface와 abstract class의 차이

  • 추상 클래스의 경우 단일 상속만 가능, 인터페이스는 다중 상속 가능
// 추상클래스는 단일 상속만 가능
abstract class Animal {
 ...구현부...
}
class Dog extends Animal {
 ... 
}

 // 인터페이스는 다중 상속 가능
 
interface Move {
  move(): void;
}

interface Speak {
  speak(text: string): void;
}

interface Actions extends Move, Speak {
  sayMyName(): void;
}

class Human implements Actions {
  move(): void {
    console.log("move");
  }
  speak(text: string): void {
    console.log(text);
  }
  sayMyName(): void {
    console.log("sayMyname!");
  }
}
  • 추상클래스는 abstract modifier(제어자)가 표기된 변수나 메소드만 구현하면 되지만, interface는 선언된 모든 변수나 메소드를 구현해야한다.
//interface => Animal Interface내의 makesound, move모두 구현해야한다.
interface Animal {
  makeSound(): void;
  move(): void;
}

class Dog implements Animal {
  makeSound(): void {
    console.log("Woof!");
  }

  move(): void {
    console.log("Moving...");
  }
}

const myDog: Animal = new Dog();
myDog.makeSound(); // 출력: "Woof!"
myDog.move(); // 출력: "Moving..."
//abstract class 
abstract class Animal {
  abstract makeSound(): void;

  move(): void {
    console.log("Moving...");
  }
}

class Dog extends Animal {
  makeSound(): void {
    console.log("Woof!");
  }
}

const myDog = new Dog();
myDog.makeSound(); // 출력: "Woof!"
myDog.move(); // 출력: "Moving..."

interface를 상속받은 class의 인스턴스의 타입은 interface로 대신할 수 있다.

아래 코드의 경우 Human class가 Actions interface를 상속받았다. 그리고 Human 인스턴스를 생성하는데, 앞서 jack의 타입을 Actions라고 명시하는 것도 가능하다. 그 이유는 Human 객체는 결국 Actions 인터페이스에 기반한 것이기 때문이다.

class Human implements Actions {
  move(): void {
    console.log("move");
  }
  speak(text: string): void {
    console.log(text);
  }
  sayMyName(): void {
    console.log("sayMyname!");
  }
}

let jack: Actions;

jack = new Human();

readonly interface property

type(사용자 정의 타입)에서와 마찬가지로 interface 내에서도 readonly property를 사용할 수 있다. private, public은 지정할 수 없다. 객체가 초기화 된 이후에는 값을 변경할 수 없다.

interface Actions extends Move, Speak {
  readonly actionNumber: number;
	...
}

class Human implements Actions {
  actionNumber = 3;
	...
}

함수 타입으로서의 인터페이스

사용자 정의 함수 타입을 type 키워드를 이용해 정의할 수 있다.

type addNum1 = (n1: number, n2: number) => number;

interface를 이용해서 function type을 정의할 수 있다. interface는 객체의 구조를 정의하는데, 함수도 결국엔 객체이기 때문에 interface를 이용해 정의가 가능하다.

interface addNum2 {
  (n1: number, n2: number): number;
}

type을 이용하는 것이 코드의 양도 적고 익명함수를 사용함에서 오는 혼란을 방지할 수 있지만 이를 알아두긴 해야한다.

interface는 JS로 컴파일 이후에는 흔적없이 사라진다. 단지 TS만의 문법이자 기능이다.

profile
자신을 개발하는 개발자!

0개의 댓글