TypeScript

Typescript - 클래스 & 인터페이스

PHM 2022. 9. 15. 17:00

클래스

- 객체는 코드로 작업을 수행하면서 사용할 수 있는 구체적인 요소들

- 클래스는 데이터를 저장하고 메소드를 실행하기 위해 메소드를 저장하는데 사용하는 데이터 구조

- 클래스를 사용하여 객체의 형태, 포함해야 하는 데이터, 클래스 기반으로 객체를 쉽게 만들 수 있으려면 어떤 메소드가 필요한지 정의할 수 있기 때문에 이를 클래스 내의 인스턴스라고 부른다.

    ㆍ객체는 클래스 내의 인스턴스인 것이다.

- 이러한 클래스를 기반으로 하면 동일한 구조, 동일한 클래스를 기반으로 하는 동일한 메소드로 여러 객체를 빠르게 복제 가능
- 이처럼 클래스는 객체의 형태, 포함해야 할 속성과 메소드를 정의하는 데 도움이 된다.

- 따라서 클래스는 객체의 생성 속도를 높여주며 객체 리터럴 표기법을 사용하는 것에 대한 대안이다.

- 클래스를 사용하여 동일한 구조와 메소드를 포함한 여러 개체를 쉽게 만들 수 있다.

 

약식 간단화

class Department {
    // private id: string;
    // private name: string;
    private employees: string[] = [];

    constructor(private id: string, public name: string) {
        // this.id = id;
        // this.name = n;
    }
}

 

- readonly : 특정 속성이 초기화되고나면 이후에는 변경 x

- protected : private와 다른 점은 이 클래스에서뿐만 아니라 이 클래스를 확장하는 모든 클래스에서 사용 가능

 

setter, getter

get mostRecentReport() {
    if(this.lastReport){
        return this.lastReport;
    }
    throw new Error('No report found.');
}

set mostRecentReport(value: string){
    if(!value){
        throw new Error("Please pass in a valid value!");
    }
    this.addReport(value);
}

 

정적 메소드

class Department {
    static fiscalYear = 2020;
    // private readonly id: string;     // readonly : 특정 속성이 초기화되고나면 이후에는 변경 X
    // private name: string;
    protected employees: string[] = []; // protected : private와 다른 점은 이 클래스에서뿐만 아니라 이 클래스를 확장하는 모든 클래스에서 사용가능

    constructor(private readonly id: string, public name: string) {
        // this.id = id;
        // this.name = n;
        console.log(Department.fiscalYear);
    }
}

- this는 클래스를 기반으로 생성된 인스턴스를 참조하기에 정적속성에 접근할 수 없다.

- 정적 속성은 인스턴스에서 유효하지 않습니다. 정적 속성과 정적 메소드의 전체적인 개념은 인스턴스와 분리되어 있다.

   그래서 this 키워드를 사용하여 접근하는 건 불가능하다.

- 클래스 내에서 정적 속성이나 메소드를 사용하고자 한다면 여기에 접근하기 위해 클래스를 이름을 써줘야한다.

 

추상 클래스

abstract class Department {
    abstract describe(this: Department) : void;
}

class ITDepartment extends Department {
    describe(): void {
        console.log('IT Department - ID: '+this.id);
    }
}

class AccountingDepartment extends Department {
    describe() {
        console.log('Accounting Department - ID: '+ this.id);
    }
}

- 추상 클래스는 일부 상위 클래스를 기반으로 하는 모든 클래스가 일부 공통 메소드 또는 속성을 공유하도록 하려는 경우 아주 유용할 수 있다.

- 추상 속성을 사용할 수도 있지만 동시에 구체적인 값, 구체적인 구현, 기본 클래스를 제공하지 않고자 한다면 상속하는 클래스가 이를 수행해야한다.

- 위의 Department를 인스턴스화 할 수 없다.

    ㆍ이는 기본적으로 상속되야할 클래스이다.

    ㆍ상속되는 클래스가 인스턴스화되고 구체적인 구현을 제공

 

싱글톤 & 개인생성자

- 싱글톤은 특정 클래스의 인스턴스를 정확히 하나만 갖도록 한다.

    ㆍ이 패턴은 정적 메소드나 속성을 사용할 수 없거나 사용하지 않고자 하는 동시에 클래스를 기반으로 여러 객체를 

        만들 수는 없지만 항상 클래스를 기반으로 정확히 하나의 객체만 가질 수 있도록 하고자 하는 경우에 유용하다.

 

- 생성자를 private 해주고 클래스 자체에서 정적 메소드 호출

- 정적 요소는 다른 모든 정적 속성(정적 메서드) 에 접근 가능

class AccountingDepartment extends Department {
    private constructor(id:string, private reports: string[]) {
        super(id, 'Accounting');
        this.lastReport = reports[0];
    }
    
    static getInstance() {
        if(AccountingDepartment.instance){
            return this.instance;
        }
        this.instance = new AccountingDepartment('d2', []);
        return this.instance;
    }
}


const accounting = AccountingDepartment.getInstance();
const accounting2 = AccountingDepartment.getInstance();

- accounting, accounting2 둘다 같은 인스턴스를 갖게 된다.

 


인터페이스

- 인터페이스는 객체의 구조를 설명한다.

- 구체적인 값이 아닌 구조만 있을 뿐이다.

 

- 사용자 정의 타입과의 차이점

    ㆍ인터페이스는 객체의 구조를 설명하기 위해서만 사용

- 인터페이스를 자주 사용하는 이유는 클래스가 인터페이스를 이해앟고 준수해야 하는 약속처럼 사용할 수 있다.

 

class Person implements Greetable {
    
}

- implements: 여러 개의 인터페이스를 구현할 수 있다는 게 상속과의 차이점이다.

    ㆍ상속은 한 클래스로부터만 상속할 수 있다.

- 인터페이스 내에 readonly 제어자도 추가 가능

    ㆍ다만 public, private 등은 지정할 수 없다.

 

interface Named {
    readonly name: string;
}

interface Greetable extends Named {
    greet(phrase: string): void;
}

- 인터페이스는 왜 나눠야 할까?

    ㆍ어떤 애플리케이션 작업을 수행하면서 어떤 객체는 name을 입력하고 greed메소드는 제외하는 한편

         다른 객체에는 greet과 name을 입력하고자 한다면 이런 식으로 나눌 수 있다.

- 인터페이스의 경우, 여러 인터페이스로부터 상속받을 수 있다는 차이가 있다.

 

interface Named {
    readonly name: string;
    outputName?: string;
}

- 문자열이어야 하는지의 여부를 선택하고자 할 때 속성 이름 다음에 물음표를 추가하여 선택적 속성을 지정

- 그러면 타입스크립트는 이 속성이 이 인터페이스를 구현하는 클래스 내에 있을 수 있지만 반드시 그렇지 않다고 인식

 

- ts 파일을 js 파일로 컴파일하면 타입스크립트가 코드를 검사할 수 있도록 하는 역할을 수행하고 나면 인터페이스에 대해 아무것도 생략되지 않는다. 그저 버려질 뿐이다.

- 그럼에도 인터페이스는 클래스나 객체가 특정 구조를 갖추도록 하고, 객체의 형태에 대한 개념을 명확하게 설명하는 강력한 기능이다.

 

- 타입스크립트 초기에는 사용자 정의 타입을 인터페이스처럼 구현하거나 사용할 수 없었기 때문이다.

  유연성이 향상되긴 했지만 객체를 사용하여 작업을 수행하고 구조를 설명하고자 한다면

  인터페이스를 사용하는 것을 권장한다.