TypeScript -11-

mh·2022년 5월 7일
0

TypeScript

목록 보기
11/17
post-thumbnail

Photo by Ryan Loughlin on Unsplash

추상화에서 클래스와 인터페이스의 차이점

추상클래스 (abstract class)

abstract class User {
    constructor(
        private firstName:string,
        protected lastName:string,
    ) {}
}

추상 클래스는 이 클래스를 상속받을 다른 클래스의 프로퍼티와 메소드를 지정함

abstract class User {
    constructor(
        private firstName:string,
        protected lastName:string,
    ) {}
    abstract sayHi(name:string):string
    abstract fullName():string
}

추상 클래스 속 추상 메소드

추상 클래스/메소드는 다른 클래스가 따라야 할 청사진을 제시함

protected는 추상클래스로부터 상속받은 클래스들이 property에 접근 할 수 있도록 허락해줌
그러나 상속받은 클래스 바깥에서는 접근 불가
private을 사용할 경우 private이 선언된 클래스 안에서만 사용가능

class Player extends User {
    sayHi(name:string) {
        return `hello ${name}. My name is ${this.fullName()}`
    }
    fullName() {
        return `${this.firstName} ${this.lastName}`
    }
}

추상 클래스를 상속했을경우 상속받은 클래스는 반드시 상속받은 추상 메소드들을 구현해야함

추상 클래스는 자기자신으로 인스턴스를 만드는것을 허용하지 않음
ex) new User() <-- (x)

단지 상속받는 클래스가 어떻게 작동하는지 알려주기 위해서 추상클래스를 사용함
어떻게 구현해야할지를 알려주는것이 아니라 어떤것을 구현해야할지를 알려줌

문제점- JavaScript에 abstract 개념이 없음
컴파일 된 js를 보면 일반적인 클래스로 출력되어있음

결국 abstract class는 컴파일 후 결과적으로 일반 class로 바뀌게 됨

그럼 왜 추상클래스를 만드나?
-> 표준화된 프로퍼티와 메소드를 갖도록 해주는 청사진을 만들기 위해서
ex) User를 만들려는 것이 아니라 Plyaer를 만들려 하는것 User를 직접적으로 만들지 않을것
그러나 컴파일 후에는 자바스크립트로 클래스로서 남아있게 됨,

이때 interface를 사용하면 됨

interface

  • 컴파일하면 JS로 바뀌지 않고 사라진다.
  • 가볍다.

class를 interafce로 바꿔보기

class를 interface로 바꾸고 constructor를 없앤다.
상속받는 클래스는 js문법인 extends 대신 implements라는 ts문법으로 대체한다.

interface User {
    firstName:string,
    lastName:string,
    sayHi(name:string):string
    fullName():string
}

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

implement 는 private,protected 프로퍼티를 사용하지 못한다. public만 가능

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()}`
    }
}

컴파일 된 JS를 보면 User interface와 Plyaer의 implements가 남아있지 않고 사라진것을 볼 수 있다.

class Player {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    fullName() {
        return `${this.firstName} ${this.lastName}`;
    }
    sayHi(name) {
        return `Hello ${name}. My name is ${this.fullName()}`;
    }
}

interface의 특징 중 하나인 프로퍼티 누적을 사용할 수도 있음(하나의 클래스에 인터페이스를 여러개 상속)

interface User {
    firstName:string,
    lastName:string,
    sayHi(name:string):string
    fullName():string
}
interface Human {
    health:number
}
class Player implements User, Human {
    constructor (
        public firstName:string,
        public lastName:string,
        public health:number
    ) {}
    fullName() {
        return `${this.firstName} ${this.lastName}`
    }
    sayHi(name:string){
        return `Hello ${name}. My name is ${this.fullName()}`
    }
}

이는 어댑터 디자인 패턴을 사용할때 유용
인터페이스를 만들어두고 팀원마다 원하는방식으로 클래스 상속이 가능

interface를 type으로 지정하기

function makeUser(user: User) {
    return "hi"
}

makeUser()

makeUser({
    firstName:"spongeBob",
    lastName:"squrePants",
    fullName: () => "abc",
    sayHi: (name:string) => "string" 
})

argument에 인터페이스를 써서 오브젝트 모양을 지정할 수 있음


function makeUser(user: User) :User {
    return {
        firstName:"spongeBob",
        lastName:"squrePants",
        fullName: () => "abc",
        sayHi: (name:string) => "string" 
    }
}

리턴값이 인터페이스 일 경우 클래스와 달리 new ClassName 이런식으로 나올 필요 없음 User interface 타입(내용물) 그대로 넣으면 됨

정리

  • interface는 오브젝트 모양을 결정 -> 클래스도 가능하다.
  • 클래스 역시 하나에 여러개의 interface를 상속할 수 있음
  • interface를 타입처럼 사용도 가능
profile
🤪🤪🤪🤪🤪

0개의 댓글