포시코딩

[TypeScript][노마드코더] #4 CLASSES AND INTERFACES(4) 본문

JavaScript

[TypeScript][노마드코더] #4 CLASSES AND INTERFACES(4)

포시 2023. 1. 22. 22:06
728x90

추상 클래스 (Abstract class)

추상 클래스 사용 예시

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

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

}

추상 클래스인 User 클래스는 그것으로부터 인스턴스를 만드는걸 허용하지 않는다. 즉, new User 불가

 

Player 클래스에게 어떻게 구현할지에 대해 알려주지 않지만

무엇을 구현해야 할 지에 대해서 알려줄 수 있다.

 

하지만 추상 클래스의 문제점은 JavaScript에 abstract 개념이 없다는 것이다. 

때문에 추상 클래스를 만들어도 결국 일반 클래스로 변한다.

-> 이말은 즉, 파일 크기도 커지고 추가 클래스가 만들어진다는 뜻 (당연히 안좋겠지?)

 

그렇다면 왜 추상 클래스를 만드는 것일까?

다른 클래스들이 표준화된 property와 메소드를 갖도록 해주는 청사진을 만들기 위해 추상 클래스를 사용한다.

하지만 JavaScript에서 일반 클래스가 되는걸 보면 소용 없다는걸 깨닳을 수 있는데

 

이 때가 interface가 필요한 시점이다. 

 

인터페이스 (Interface)

인터페이스 사용 예시

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

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

extends가 아닌 implements로 상속받는거 주의

 

잘 작성한거 같은데 에러가 나고 있다.

interface를 상속할 때에는 property를 private으로 만들지 못하기 때문이다.

public으로 변경해주면 해결된다. 

 

 

정리하자면

interface는 클래스의 모양을 알려준다는 점에서 매우 유용하다. 

추상 클래스를 사용할 때는 그 클래스들이 JavaScript에 보였던 반면, 

interface를 상속받을 경우 JavaScript 코드로 트랜스파일 되지 않는다.

 

다만, interface를 상속받는것에도 문제점이 존재하는데 

private property들을 사용하지 못한다는 것과 

추상 클래스에서는 constructor가 귀찮은 부분을 해주도록 할 수 있지만 interface에서는 그러지 못한다. 

 

원한다면 하나 이상의 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(): string {
        return `${this.firstName} ${this.lastName}`
    }
    sayHi(name: string): string {
        return `Hello ${name}. My name is ${this.fullName()}`
    }
}

 

그리고 당연하지만

type으로 interface를 사용할 수도 있다.

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

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

makeUser({
    firstName: 'nico', 
    lastName: 'las', 
    fullName: () => 'xx', 
    sayHi: (name) => 'string'
});
function makeUser(user: User): User {
    return {
        firstName: 'nico', 
        lastName: 'las', 
        fullName: () => 'xx', 
        sayHi: (name) => 'string'
    }
}

 

728x90