본문 바로가기
TypeScript

[Typescript] 클래스, 추상클래스, 인터페이스, 그리고 차이

by 새우하이 2021. 12. 9.

클래스

타입스크립트 클래스

타입 스크립트의 클래스도 ES6의 클래스와 상당히 유사합니다. 클래스도 사실 함수이고 기존 프로토타입 기반 패턴의 syntatic sugar일 뿐입니다. 하지만 몇가지 Typescirpt만의 확장 기능이 있습니다.

정의

타입 스크립트에서는 클래스 몸체에 클래스 프로퍼티를 사전 선언해야합니다.

class 클래스 이름 {
  [private | protected | public] property name[?]: property type[...]
}

클래스 선언문의 기본 형태입니다.

class Person {
    name: string;

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

    walk() {
        console.log(`${this.name} is walking.`);
    }
}

const person1 = new Person('park jiwon');
person1.walk();

접근제한자

접근 제한자는

  • public
  • private
  • protected
    를 지원합니다.

접근 제한자를 명시하지 않으면, 다른 클래스 기반이 암묵적으로 protected로 지정되는 것과 다르게 타입스크립트에서는 접근제한자를 생략한 클래스 프로퍼티나 메소드는 암묵적으로 public이 선언됩니다. 따라서 public은 생략 가능.

접근 제한자에 따른 접근 가능성

class Foo {
    public x: string;
    protected y: string;
    private z: string;

    constructor(x: string, y: string, z: string) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

const foo = new Foo('x', 'y', 'z');

클래스 내부

우선 public, protected, private 접근 제한자 모두 클래스 내부에서는 참조가 가능합니다.

클래스 인스턴스(클래스 외부)

console.log(foo.x); // 참조 가능
console.log(foo.y); //'y' 속성은 보호된 속성이며 'Foo' 클래스 및 해당 하위 클래스 내에서만 액세스할 수 있습니다.
console.log(foo.z);//'z' 속성은 private이며 'Foo' 클래스 내에서만 액세스할 수 있습니다.
class Bar extends Foo {
    constructor(x: string, y: string, z: string) {
        super(x, y, z);
        console.log(this.x); // 참조 가능
        console.log(this.y); // 참조 가능
        console.log(this.z); //'z' 속성은 private이며 'Foo' 클래스 내에서만 액세스할 수 있습니다.
    }
}

constructor() 생성자 파라미터에 접근 제한자 선언

생성자 파라미터에도 접근제한자를 선언할 수 있습니다. 이때 접근 제한자가 사용된 생성자 파라미터는 암묵적으로 클래스 프로퍼티로 선언되고 생성자 내부에서 별도 초기화 없이도 암묵적으로 수행됩니다.

만약에 생성자 파라미터에도 접근제한자를 선언하지 않으면 생성자 내부에서만 유효한 지역변수가 돼 버립니다. 그럼 생성자 밖에서는 참조가 불가능해집니다.

readonly

typescript는 readonly 키워드 사용이 가능합니다. readonly가 선언된 클래스 프로퍼티는 선언 시와 생성자 내부에서만 값을 할당할 수 있고 그 외의 경우에는 읽기만 가능합니다.

class Foo {
    private readonly MAX_LEN: number = 65535;
    private readonly MSG: string;
    constructor() {
        this.MAX_LEN = 30;
        this.MSG = 'Hello'
    }
    log = () => {
        this.MAX_LEN = 10;
        console.log(`MAX_LEN : ${this.MAX_LEN}`);
    }
}

static

ES6 클래스에서 static 키워드를 제공합니다. 하지만 ES6의 static은 메소드 전용이라 프로퍼티에서는 활용할 수 없습니다. typescript는 static 키워드를 프로퍼티에도 활용할 수 있습니다.

정적 클래스 프로퍼티는 인스턴스가 아닌 클래스 이름으로 호출하고, 클래스의 인스턴스를 사용하지 않아도 호출할 수 있습니다.


정적 메소드는 인스턴스로 호출 불가능.

추상 클래스

추상 클래스는 추상 메소드를 가질 수 있는 클래스 입니다. 추상 메소드는 내용이 없이 메소드 이름과 타입만이 선언된 메소드를 말하고 선언시에 abstract 키워드를 사용합니다. 추상 클래스는 자신의 속성이나 메서드 앞에 abstract를 붙여 나를 상속하는 다른 클래스에서 이 속성이나 메서드를 구현하게 합니다. 또한 추상 클래스로는 객체 인스턴스를 생성할 수 없습니다. 상속용으로만 가능합니다.

 


Interface랑 뭐가 다른지??
인터페이스는 모든 메소드가 추상 메소드 입니다. 추상 클래스는 추상 메소드만 포함할 수 있는 것이 아니라 실제 구현이 있는 메소드도 포함할 수 있습니다.
좀 더

인터페이스

타입스크립트는 객체의 타입을 정의할 수 있는 interface라는 키워드를 제공합니다. 인터페이스는 여러가지 타입을 갖는 프로퍼티로 이뤄진 새로운 타입을 정의하는 것과 유사합니다.

인터페이스는 프로퍼티와 메소드를 가질 수 있는 점에서 클래스와 유사하지만 직접 인스턴스를 생성할 수 없고 모든 메소드는 추상메소드입니다.

인터페이스 선언

interface 인터페이스 이름{
      property name[?]: property type[,...]
}

인터페이스는 객체의 타입을 정의하는 것이 목적이기 때문에, {}로 프로퍼티이름과 프로퍼티 타입을 나열하는 형태로 사용합니다.

변수와 인터페이스

interface Todolist {
    id: number;
    title: string;
    done: boolean;
}

let todo: Todolist;

todo = { id: 1, title: 'typescript 학습하기', done: false };

인터페이스는 변수의 타입으로 사용이 가능합니다. 인터페이스를 타입으로 선언한 변수는 해당 인터페이스를 준수해야합니다.
그리고 인터페이스를 사용해서 함수의 파라미터 타입을 선언할 수도 있습니다.

함수와 인터페이스

인터페이스는 함수의 타입으로도 사용할 수 있습니다.
함수의 인터페이스에는 타입이 선언된 파라미터 리스트와 리턴 타입을 정의하고 함수는 이를 준수해야합니다.

interface GetName  {
    (name: string): string;
}

const getName: GetName = () => {
    return "jiwon"
}

클래스와 인터페이스

interface ITodolist{
    id: string;
    title: string;
    done: boolean;
    pass: () => void;
};

class Todolist implements ITodolist{

    constructor(
        public id: string,
        public title: string,
        public done: boolean
    ) { }
    pass = () => {
        console.log("NO!!!")
    }
};
const todos = new Todolist('efese-fefe1', 'typescript 공부하기', true);
console.log(todos);

클래스 선언문의 implements 뒤에 인터페이스를 선언하면 클래스는 지정된 인터페이스를 반드시 구현해야합니다. 인터페이스는 프로퍼티와 메소드를 가질 수 있지만 직접 인스턴스를 생성할 수는 없습니다. 그리고 인터페이스는 프로퍼티 뿐만아니라 메소드도 포함할 수 있습니다. 단, 모든 메소드는 추상메소드여야 합니다. 따라서 인터페이스를 구현하는 클래스는 인터페이스에서 정의한 프로퍼티와 추상 메소드를 반드시 구현해야합니다.

덕 타이핑

interface IDeveloper{
    coding(): void;
}

class FrontEnd implements IDeveloper{
    coding() {
        console.log("React!")
    }
}

class BackEnd {
    coding() {
        console.log("Spring!");
    }
}

const frontEndDeveloper = new FrontEnd();
const backEndDeveloper = new BackEnd();

const startCoding = (developer: IDeveloper): void => {
    developer.coding();
}

startCoding(frontEndDeveloper);
startCoding(backEndDeveloper);

FrontEnd 클래스는 IDeveloper 인터페이스를 상속받아 생성됐고, 이 클래스를 통해 생성된 인스턴스인 frontEndDeveloper는 startCoding의 파라미터인 IDeveloper의 타입과 일치합니다.
반면 backEndDeveloper는 IDeveloper 인터페이스를 구현하지 않았지만 coding 메소드를 갖고 있습니다.
이 상태에서 startCoding 함수에 IDeveloper 인터페이스를 구현하지 않은 BackEnd의 인스턴스 backEndDeveloper를 파라미터로 전달해도 에러가 나지 않습니다.

Typescript에서는 해당 인터페이스에서 정의한 프로퍼티나 메소드가 있다면 해당 인터페이스를 구현한 것으로 인정합니다. 그리고 이것을 덕타이핑 혹은 구조적 타이핑이라고 합니다.

인터페이스는 개발 단계에서 도움을 주기위해 제공되는 기능입니다. 즉 트랜스 파일링시에 삭제되는 기능입니다.

interface Jiwon {
    name: string;
  }

function getName(jiwon: Jiwon):void {
    console.log(`이름은 ${jiwon.name} 입니다.`)
}
const me = { name: 'Park jiwon', age: 26 };
getName(me);

는 트랜스파일링 이후

function getName(jiwon) {
    console.log("\uC774\uB984\uC740 ".concat(jiwon.name, " \uC785\uB2C8\uB2E4."));
}
var me = { name: 'Park jiwon', age: 26 };
getName(me);

이와 같이 사라집니다.

상속

인터페이스는 extends 키워드를 사용해서 인터페이스 또는 클래스를 상속받을 수 있습니다.
그리고 복수의 인터페이스를 상속받을 수도 있습니다.

interface Person{
    name: string;
    age?: number;
}

interface Developer extends Person{
    skills: string[];
}

const Jiwon: Developer = {
    name: 'park jiwon',
    age: 26,
    skills: ['html', 'css']
}

그리고 인터페이스는 클래스도 상속이 가능합니다.

class Person{
    constructor(public name:string, public age:number) { };
}

interface Developer extends Person{
    skills: string[];
}

const Jiwon: Developer = {
    name: 'park jiwon',
    age: 26,
    skills: ['html', 'css']
}

클래스의 모든 멤버가 상속되지만 구현까지는 상속하지 않습니다.

'TypeScript' 카테고리의 다른 글

typescript 제네릭  (0) 2022.01.08
TypeScript union타입, any타입, unknown 타입  (0) 2021.10.25
TypeScript 설치와 타입지정  (0) 2021.10.24

댓글