[하루 30분 러닝 타입스크립트] 클래스(2)

✨ 클래스 확장

클래스 역시 extends 키워드를 사용하여 확장할 수 있습니다.

class Teacher {
    teach() {
        console.log("teach")
    }
}

class StudentTeacher extends Teacher {
    learn() {
        console.log("learn")
    }
}

할당 가능성 확장

파생된 인스턴스는 기본 클래스 또는 하위 클래스를 충족하는데 사용할 수 있습니다.

class Lesson {
    subject: string

    constructor(subject: string){
        this.subject = subject;
    }
}

class OnlineLesson extends Lesson {
    url: string;

    constructor(subject: string, url: string) {
        super(subject)
        this.url = url;
    }
}

let lesson: Lesson
lesson = new OnlineLesson("coding", "coding.com") // OK

타입스크립트의 구조적 타입에 따라 하위 클래스의 모든 멤버가 동일한 타입의 기본 클래스에 존재하는 경우 기본 클래스를 하위 클래스 대신 사용할 수 있습니다.

class Lesson {
    subject: string = "coding"
}

class OnlineLesson extends Lesson {
    url?: string;
}

let lesson: OnlineLesson
lesson = new Lesson(); // OK

재정의된 생성자

자바스크립트 규칙에 따르면, 하위 클래스의 생성자는 this 또는 super에 접근하기 전에 반드시 기본 클래스의 생성자를 호출해야 합니다.

타입스크립트에서는 super() 를 호출하기 전, this 또는 super에 접근 하려 할 경우, 타입 오류로 보고합니다.

class GradesTally {
    grades: number[] = [];

    addGrades(...grades: number[]){
        this.grades.push(...grades);
        return this.grades.length
    }
}

class ContinuedGradesTally extends GradesTally {
    constructor(previousGrades: number[]) {
        this.grades = [...previousGrades]
        // ERROR 'super' must be called before accessing 'this' in the constructor of a derived class.(17009)
        super();
    }
}

재정의된 메서드

하위 클래스의 메서드는 기본 클래스의 메서드에 할당될 수 있는 한 재선언을 할 수 있습니다.

재선언하는 메서드의 반환 타입이 기존의 메서드와 같으면 된다.

class GradeCounter {
    countGrades(grades: string[], letter: string){
        return grades.filter(grade => grade === letter).length
    }
}

class FailureCounter extends GradeCounter {
    countGrades(grades: string[]){
        return super.countGrades(grades, "F")
    }
		// OK
}

class AnyFailureChecker extends GradeCounter {
    countGrades(grades: string[]){
        return super.countGrades(grades, "F") !== 0
    }
    /* ERROR
    Property 'countGrades' in type 'AnyFailureChecker' is not assignable to the same property in base type 'GradeCounter'.
    Type '(grades: string[]) => boolean' is not assignable to type '(grades: string[], letter: string) => number'.
    Type 'boolean' is not assignable to type 'number'.
     */
}

재정의된 속성

재정의된 메서드와 마찬가지로, 구조적으로 일치한다면, 동일한 이름으로 속성을 재정의 할 수 있습니다.

class Grade {
    grade?: number;
}

class Grade2 extends Grade {
    grade: number;

    constructor(grade: number){
        super();
        this.grade = grade;
    }
}

✨ 추상 클래스

하위 클래스가 특정 메서드를 제공할 것을 예상하고 기본 클래스를 만드는 방법이 유용할 수 있습니다. 이를 추상화라 하고 타입스크립트의 abstract 키워드를 추가하여 만들 수 있습니다.

abstract class School {
    readonly name: string;

    constructor(name: string){
        this.name = name
    }

    abstract getStudents(): string[]
}

class Preschool extends School {
    getStudents() {
        return ["A", "B"]
    }
}

let school: School;
school = new Preschool("ABC School");
school = new School("ABC School");
// ERROR Cannot create an instance of an abstract class.

✨ 멤버 접근성

타입스크립트의 클래스 지원은 자바스크립트의 # 프라이버시 보다 먼저 만들어졌습니다. 또한 private 이외의 다른 프라이버시 정의 집합을 허용합니다

private선언은 자바스크립트에서도 존재하기 때문에, 런타임에도 존재합니다.

  1. public : 모든 곳에서 접근 가능
  2. protected : 클래스 내부 또는 하위 클래스에서만 접근 가능
  3. private : 클래스 내부에서만 접근 가능
class Access {
    isPublic = 0;
    public isPublicExplicit = 1;
    protected isProtectedExplicit = 2;
    private isPrivateExplicit = 3;
    #isPrivate = 4;
}

class Child extends Access {
    run() {
        this.isPublic = 10; // OK
        this.isPublicExplicit = 11; // OK
        this.isProtectedExplicit = 12; // OK
        this.isPrivateExplicit = 13;
        // ERROR Property 'isPrivateExplicit' is private and only accessible within class 'Access'.
        this.#isPrivate = 14;
        // ERROR Property '#isPrivate' is not accessible outside class 'Access' because it has a private identifier.
    }
}

new Child().isProtectedExplicit = 20;
// ERROR Property 'isProtectedExplicit' is protected and only accessible within class 'Access' and its subclasses.

정적 필드 제한자

자바스크립트는 static 키워드를 사용해 클래스 자체에서 멤버를 선언합니다.

타입스크립트에서는 static 키워드를 readonly 키워드와 함께 사용할 수 있도록 지원합니다.

class Question {
    protected static readonly answer: "ABC";
}

Question.answer
//ERROR Property 'answer' is protected and only accessible within class 'Question' and its subclasses.