[TS] 타입스크립트 class와 interface

seung·2022년 5월 3일
0

class


class 키워드를 이용하여 키워드를 만들며, class 이름은 보통 대문자로 시작한다.

new를 이용하여 class를 통해 객체를 만들 수 있다.

자바스크립트로 컴파일되면 es5의 경우 function으로 변경된다.

class Department {
	id: number;
	name: string;

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

const d = new Department(1, 'seung');

생성자

strict 모드에서는 프로퍼티를 선언하는 곳 또는 생성자에서 값을 할당해야 한다.

프로퍼티를 선언하는 곳 또는 생성자에서 값을 할당하지 않는 경우에는 !를 붙여서 위험을 표현한다.

클래스의 프로퍼티가 정의되어 있지만, 값을 대입하지 않으면 undefined 이다.

class Person {
  name: string = 'seung';
  age!: number; // 그냥 age 라고만 정의하면 에러 발생하므로 ! 붙여서 위험을 표현
}

const p = new Person();
console.log(p.age); // ❗️undefined

상속

자바스크립트와 동일하게 extends 키워드를 이용하여 상속한다.

class

추상 클래스 & 추상 메소드

  • class 앞에 abstract 키워드 붙여서 사용
  • 추상 클래스는 인스턴스화 할 수 없고 확장되어야 하는 클래스
  • 추상 클래스 내에 추상 메소드를 작성하고 자식 클래스에서 추상 메소드의 내부 코드를 완성 시켜야 함
 abstract class Department {
  constructor(public id: number, public name: string) {}

  abstract descript(this: Department): void;
}

class ITDepartment extends Department {
  constructor(id: number) {
    super(id, 'IT');
  }

  descript() {
    console.log(`IT Department - ID: ${this.id}`);
  }
}

private 생성자 (싱글톤 패턴)

  • 하나의 인스턴스만 생성하고 사용하기 위함
  • 생성자 앞에 private 키워드를 붙여 사용
  • 클래스 내부에 정적 instance 변수 및 getInstance 메소드를 이용
class ITDepartment extends Department {
  private static instance: ITDepartment;

  private constructor(id: number) {
    super(id, 'IT');
  }

  static getInstance() {
    if (ITDepartment.instance) {
      return this.instance;
    }
    this.instance = new ITDepartment(1);
    return this.instance;
  }

  descript() {
    console.log(`IT Department - ID: ${this.id}`);
  }
}

const it = ITDepartment.getInstance();


interface


  • 인터페이스는 사용자 정의 타입으로 사용
  • 객체의 구조를 정의
  • 특정한 기능들이 요구되는 경우 유용
  • readonly 제어자 가능 / ~~public, private 등 불가능~~
interface Person {
  name: string;
  age: number;
  greet(phrase: string): void;
}

let user1: Person;

user1 = {
  name: 'Seung',
  age: 28,
  greet(phrase: string) {
    console.log(`${phrase} ${this.name}`);
  },
};

💡 여기서, 궁금한 점은 사용자 정의 타입으로 사용한다면 type Person = { ... } 과 똑같지 않나?
인터페이스는 객체의 구조를 설명하기 위해서만 사용한다.
또한, 인터페이스를 여러 클래스간 공유하며 해당 구조로 만들어져야 한다고 나타낼 수 있다.


인터페이스 구현 (implements)

  • 인터페이스는 쉼표를 이용하여 여러 인터페이스를 구현할 수 있음
  • 인터페이스를 구현한 클래스는 인터페이스 내 구조에 있는 내용 외에 더 많은 요소 입력 가능
interface Greetable {
  name: string;
  greet(phrase: string): void;
}

class Person implements Greetable {
  age:number = 28;

  constructor(public name: string) {}

  greet(phrase: string) {
    console.log(`${phrase} ${this.name}`);
  }
}

인터페이스 상속 (extends)

인터페이스간 상속하여 확장시킬 수 있다.

❗️ 클래스와 다르게 두 개 이상의 인터페이스를 상속받을 수 있다.

interface Named {
  readonly name: string;
}
interface Aged {
	age: number;
}

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

함수 타입으로서의 인터페이스

type 대신 인터페이스로 사용자 함수 타입을 나타낼 수 있다.

// type AddFn = (a: number, b: number) => number;

interface AddFn {
  (a: number, b: number): number;
}

const add: AddFn = function(num1: number, num2: number) {
  return num1 + num2;
}

선택적 매개변수 & 속성

프로퍼티 식별자 뒤에 ?를 붙여 사용하며, 해당 변수는 선택적으로 구현해도 된다는 표시이다.

interface Named {
  readonly name?: string;
}

class Person implements Named {
  name?: string;
  constructor(n : string) {
    if (n) {
      this.name = n;
    }
  }
}

Declaration Merging

동일한 이름의 인터페이스를 여러개 생성하면 나중에 해당 인터페이스의 이름으로 사용할 때 여러개가 합쳐진 상태로 사용 가능하다.

interface MergingInterface {
  a: string;
}
interface MergingInterface {
  b: string;
}

let mi: MergingInterface = {
  a: 'a',
  b: 'b',
};


접근 제어자


  • public: 모든 곳에서 접근 가능
  • private: 자신의 클래스 내에서만 접근 가능 / 외부 접근 불가능 / 확장 클래스 접근 불가능
    • 프로퍼티나 메서드 이름 앞에 _를 붙여 표현하는 관습 있음
  • protected: 외부 접근 불가능 / 확장 클래스 접근 가능

💡 readonly: 특정 속성이 초기화 후엔 변경될 수 없음


생성자에 접근 제어자 적용

생성자 매개변수에 접근제어자 표시를 통해 간략하게 변수 초기화 가능

💩 변경 전

class Department {
	private readonly id: number;
	public name: string;

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

✨ 변경 후

class Department {
  constructor(private readonly id: number, public name: string) {}
}
profile
🌸 좋은 코드를 작성하고 싶은 프론트엔드 개발자 ✨

0개의 댓글