[TS series] TS 기본문법 #10

_sqrlkoo·2023년 1월 10일
0

TypeScript

목록 보기
10/12
post-thumbnail

Interface를 들어가기 전에..

Interface를 처음 마주한 느낌은 type alias 강의와 굉장히 비슷하다는 생각이 들었다.

실제로 강의에서도 타입 별칭과 굉장히 유사하다고 말한다.

그럼 바로 interface에 대해 알아보자!

Interface

Interface는 typescript에서 가장 흔히 사용되는 기능이다.

type alias와 굉장히 유사하며,

객체의 형태를 묘사하는 데에 사용됩니다, 오직 객체에만 사용하죠!

구문은 이런 형태입니다!

interface Point {
  x : number;
  y : number;
}

type Point = {
  x : number;
  y : number;
}

이전 type alias와 차이점을 느끼지 못했나요?

interface는 type alias와 다르게 등호를 사용하지 않습니다.

그리고 오직 객체에만 사용하기 때문에 유니온 타입에 인터페이스를 쓰긴 불가능하지만 타입 별칭은 사용 가능합니다!

Interface의 method

다음으로 살펴볼 내용은 인터페이스에 메서드를 추가하는 겁니다.

interface Person {
    readonly id : number;
    first : string;
    last : string;
    nickname ?: string;
}

const thomas: Person = {
    first : "Thomas",
    last : "Hardy",
    nickname : "Tom",
    id : 1231
};

다음과 같은 코드에 객체가 어떤 메서드를 포함하며, 메서드가 받고 반환하는 타입에서 객체 형태를 묘사하겠습니다.

쉬운 예시를 들어보겠습니다.

interface Person {
    readonly id : number;
    first : string;
    last : string;
    nickname ?: string;
  	sayHi: () => string;
}

const thomas: Person = {
    first : "Thomas",
    last : "Hardy",
    nickname : "Tom",
    id : 1231
};


이제 thomas라는 객체는 sayHi가 없다는 오류를 바로 표시합니다.

그럼 sayHi를 추가하고 문자열로 지정을 하면 오류가 사라지겠죠?

아닙니다!

위 사진처럼 오류를 출력합니다.

왜 그럴까요??

이 위에서 정의한 sayHi는 문자열이어야 한다는 게 아닙니다.

sayHi는 메서드여야 한다고 정의했습니다.

그럼 이렇게 메서드로 작성하면 오류가 출력되지 않습니다!

interface Person {
    readonly id : number;
    first : string;
    last : string;
    nickname ?: string;
    sayHi: () => string;
}

const thomas: Person = {
    first : "Thomas",
    last : "Hardy",
    nickname : "Tom",
    id : 1231,
    sayHi: () => {
        return "hi! hi!"
    }
};

여기서 만약 sayHi 메서드에 인수를 적용하면 어떻게 될까요?


오류를 출력합니다.

그리고 메서드를 묘사하는 데는 다른 구문을 사용할 수도 있는데

아래 주석된 코드와 밑에 있는 코드는 같은 코드입니다.

interface Person {
    readonly id : number;
    first : string;
    last : string;
    nickname ?: string;
    // sayHi: () => string;
     sayHi(): string;
}

const thomas: Person = {
    first : "Thomas",
    last : "Hardy",
    nickname : "Tom",
    id : 1231,
    sayHi: () => {
        return "hi! hi!"
    }
};

Interface 다시 열기

interface를 작성한 이후에도 인터페스를 다시 열어 새로운 프로퍼티를 추가할 수 있습니다.

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

interface Dog {
    breed : string;
}

const me: Dog = {
    name : "jangwoo",
    age : 26,
}

breed를 추가한 이후에 다시 breed를 선언하지 않으면 오류를 출력합니다.

인터페이스가 제 3자 라이브러리에 있거나 무언가 추가하고 싶을 때 사용하는 방법입니다.

전체를 덮어쓰기 하더나 삭제하는 것을 원하지 않고, 프로퍼티를 추가할 때 이렇게 사용할 수 있습니다.

Interface의 확장

인터페이스의 또 다른 유용한 기능은 인터페이스의 확장, 즉 타 인터페이스로부터의 상속 기능입니다.

객체 기반 프로그래밍에서 부모 클래스로부터 기능을 상속하는 클래스가 있는 것과 유사한 개념이 인터페이스에도 있습니다.

위의 Dog 인터페이스에는 name, age, breed 가 있습니다.

그럼 저는 안내견에 관련된 또 다른 인터페이스가 필요하다고 가정 해봅시다.

다른 타입으로 별개로 취급되는거죠

Service Dog에도 name, age, breed가 포함되지만 이번에는 job도 필요할 겁니다.

폭발물 또는 마약탐지견 등을 돕는 안내견일 수도 있겠죠!

이 모든 내용을 처음부터 작성하는 게 아니라 extends 키워드를 추가한 뒤 타입의 상속을 원하는 인터페이스의 이름을 입력하면 됩니다.

그러면 extends Dog 키워드 덕분에 ServiceDog에 요구되는 name, age, breed가 자동으로 포함됩니다.

그리고 jobdmf 추가해 넣을 수 있겠죠!

job은 유니온 리터럴 타입으로

bomb, guide dog 식이라고 해봅시다.

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

interface Dog {
    breed : string;
}

interface ServiceDog extends Dog {
    job : "bomb" | "guide dog";
}

이런식으로 추가해주면 됩니다.

이제 chewy라는 객체를 만들어봅시다.

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

interface Dog {
    breed : string;
}

interface ServiceDog extends Dog {
    job : "bomb" | "guide dog";
}

const chewy: ServiceDog = {
    name : "jangwoo",
    age : 25,
    breed : "lab"
}

만약 ServiceDog 타입에서 job을 빼면 어떻게 될까요?

이런식으로 오류를 출력합니다.

당연하게도 여기서 리터럴타입에서 작성한 것 외의 다른 항목을 넣으면 오류가 생깁니다.

extends의 다중 상속

이제 여러 개의 인터페이스를 확장하고, 다수의 상속이 있는 인터페이스의 간단한 예시를 살펴보겠습니다.

아주 평범하게 인터페이스 Human으로 만들어 보겠습니다.

interface Human {
    name : string;
}

interface Employee {
    readonly id : number;
    email : string;
}

interface Engineer extends Human, Employee {
    level : string;
    languages : string[];
}

const jangwoo: Engineer = {
    name : "jangwoo",
    email : "jangwoo@gamil.com",
    id : 123123,
    level : "junior",
    languages : ["JS","Python"]
}

이런식으로 다중 상속이 가능합니다.

Interface 와 type alias의 차이점

마지막으로 필자가 가장 궁금했던 interface와 type alias의 차이점을 비교해보도록 하겠습니다.

첫번째로, 인터페이스는 객체만의 형태를 묘사할 수 있습니다.

type color = "red" | "Orange" | "blue";

interface color2 = "red" | "Orange" | "blue"; // error

두번째로, 인터페이스로는 이미 생성한 인터페이스를 다시 열어서 내용을 추가하는 것이 가능하지만 타입으로는 그럴 수 없습니다.

type cat = {
    name : string;
}

type cat = {
    age : number;
}
// error

interface cat {
    name : string;
}
interface cat {
    age : number;
}
// 이런식으로 내용을 추가 할 수 있습니다.

그리고 프로퍼티의 확장, 즉 다른 인터페이스를 상속하는 경우에 extends를 사용해 다른 인터페이스로 확장을 했지만 type alias는 &를 이용한 교차타입을 사용해야 합니다.

type Name = {
  name : string;
}

type Person = Name & {
  age : number;
}

const person: Person = {
  name : "jerry",
  age : 24
}
// type alias의 상속

interface Name {
  name : string;
}

interface Person extends Name {
  age : number;
}

const person: Person = {
  name : "jerry",
  age : 24
}
// interface의 상속

0개의 댓글