TypeScript Class

YEZI🎐·2023년 6월 23일
0

TypeScript

목록 보기
3/8

Class

class + 파스칼 케이스(pascal case) + {}

  • JavaScript : ES2015의 새로운 문법
  • TypeScript : C#에서 유래된 것이 많음
  • 일부 기능은 TS에서만 존재하는 고유 문법으로 컴파일 후 사라짐
class Person{
  /* 필드 */
  name: string;	
  age: number;
  readonly location: string = 'korea';	// readonly 수정 불가능 
  
  /* 생성자 */
  constructor(name: string, age: number){
    this.name = name;
    this.age = age;
  }
  
  /* 메서드 */
  introduce(): string{
  	return `${this.name}의 나이는 ${this.age}입니다.`
  }
}

const p = new Person('yeahzing', 125);	// new를 붙이면 class가 인스턴스화 함

필드

  • 일종의 속성
  • contructor()에서 받은 파라미터의 데이터 타입을 지정
  • public으로 사용 가능
  • 필드 앞에 readonly를 붙이면 수정 불가능

생성자

  • 클래스가 인스턴스화가 되는 순간에 기본 값 담당(초기화)

메서드

  • 객체(클래스)에서는 행동을 뜻함
  • 클래스가 갖고 있는 함수

Getter & Setter

필드에 접근할 권한을 가진 제어자이다.

  • getter는 있고 setter는 없는 경우 => 속성은 자동으로 readonly가 된다.
  • setter 매개변수의 타입이 지정되지 않은 경우, getter의 반환 타입에서 타입을 추론한다.

public한 필드에 접근할 때 . 연산자를 붙이면 간단하게 접근 할 수 있다.

class Person{
  name: string;	
  age: number;

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

const p = new Person('yeahzing', 125);

console.log(p.age);	// yeahzing

하지만 필드에 private이 붙으면 . 연산자로 접근 할 수 없다.
(보통 숨겨진 속성일 경우 앞에 _를 붙인다.)

private _age: number;	// private
console.log(p._age);	// error

Getter

이때 private을 외부에서 접근할 수 있도록 해주는 것이 getter이다.
또한, 외부에서 접근 했을 때 어떻게 보여줄지를 제어할 수 있다.

class Person{
  name: string;	
  private _age: number;	// private

  constructor(name: string, age: number){
    this.name = name;
    this._age = age;
  }
  
  // getter
  get age(){
    return this._age + '세 입니다.';
  }
}

const p = new Person('yeahzing', 125);

console.log(p._age);	// 125세 입니다.

Setter

class Person{
  name: string;	
  private _age: number;	// private

  constructor(name: string, age: number){
    this.name = name;
    this._age = age;
  }
  
  // getter
  get age(){
    if(this._age === 0){
      return '설정되지 않았습니다.';
    }
    return this._age + '세 입니다.';
  }

  // setter
  set age(age){
    if(typeof age === 'number){
       this._age = age;
    }
    
    this._age = 0;
  }
}

const p = new Person('yeahzing', 125);

console.log(p._age);	// 125세 입니다.

Extends

  • 상속
  • 확장
class 기본 {
  result() {
    return 'Base';
  }
}

class 파생1 extends 기본 {
  // 기본class 가 확장되어 파생class가 됨
}

class 파생2 extends 기본 {
  // 오버라이딩(Overriding)
  // 상위 클래스의 메서드를 하위 클래스가 재정의
  result() {
    return 'Derived';
  }
}

const de1 = new 파생1();
const de2 = new 파생2();

console.log(de1.result());	// Base	
console.log(de2.result());	// Derived	

Super

  • 기본 클래스 호출 시 사용
  • 생성자에서 super 사용 시 this 사용 전 호출되어야 함
    this 호출 이후에 super가 호출되면 error
class Animal {
  name: string;
  
  constructor(name: string) {
    this.name = name;
  }
  
  sayName() {
    return `동물의 이름은 ${this.name}`;
  }
}

class Person extends Animal {
  constructor(name: string) {
    // Animal의 생성자를 쓰고 싶은 경우
    // console.log(this);  => error
    super(name);
  }
  
  sayName() {
    return `사람의 이름은 ${this.name}`;
    // 여기서 this는 super로 받아온 Animal 클래스
    
    // super.sayname() 으로도 super 사용 가능
    // => 동물의 이름은 YEZI
  }
}

const person = new Person('YEZI');
console.log(person.sayName());  // 사람의 이름은 YEZI

접근 제어자

  • 속성, 메서드에 접근을 제한할 수 있다.
  • 클래스 내부 구현 정보를 적당히 공개하여 일부분만 노출
    • API와 비슷한 흉내를 낼 수 있음
    • 타입 시스템을 이용해 규칙을 강제할 수 있음
  • 종류
    • public : 어디서나 접근 가능 (기본값)
    • protected : 해당 클래스와 서브 클래스(파생 클래스)에서만 접근 가능
    • private : 해당 클래스의 인스턴스에서만 접근 가능
class Person {
  name: string;  // public
  private age: number;
  protected gender: 'M' | 'F';
  
  constructor (name: string, age: number, gender: 'M' | 'F') {
    this.name = name;
    this.age = age;
    this.gender = gender;
  }
  
  sayName() {
    return `이름: ${this.name}`;
  }
  
  protected sayAge() {
    return `나이: ${this.age}`;
  }
  
  private sayGender() {
    return `성별: ${this.gender}`;
  }
}

const p = new Person ('yezi', 125, 'M');

console.log(p.age)  // error
console.log(p.sayAge()); // 나이 : 125

class Me extends Person {
  construtor(name: string, age: number, gender: 'M' | 'F') {
    super(name, age, gender)
  }
  
  sayInfo() {
    return `이름: ${super.sayName()}, 
            나이: ${super.sayAge()},
            성별: ${super.sayGender()}`;  // error
    // sayGender는 private이라 접근 불가능
}

Static

  • 클래스의 속성과 메서드를 new로 인스턴스화 하지 않고 호출 가능
  • 접근 제어자 활용 가능
  • 몇 가지 정적이름은 사용할 수 없음
    • 클래스는 그 자체로 new로 호출할 수 있는 함수이기 때문
    • ex) function.name
class StaticClass {
  type1 = 'Type1';
  static type2 = 'Type2';
  private static type3 = 'Type3';
  
  static getType() {
    return this.type3;
    /* ↑ 같은 거 ↓ */
    // return StaticClass.type;
  }
}
console.log(StaticClass.type1)  // 생성자 없이 속성 지정 시 접근 불가능, 인스턴스화 되지 않았기 때문
console.log(StaticClass.type2)  // 생성자 없어도 static 속성은 접근 가능
console.log(StaticClass.type3)	// private 제어자이기 때문에 접근 불가능
console.log(StaticClass.getType)  // output: 'Type3'

Readonly

  • 접근 제어자가 있는데 readonly를 사용하는 이유
    • 접근 제어자여도 수정이 가능하기 때문
    • readonly는 말 그대로 수정이 불가능한 읽기만 가능
class Person {
  name: string;
  readonly age: number;
  
  constructor (name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  
  setAge(newAge: number) {
    this.age = newAge;  // error, readonly 수정 못 함
  }
}

const p = new Person();

p.age = 30;  // error, readonly 수정 못 함

추상 클래스

  • javascript에서는 존재하지 않음
  • abstract라는 키워드를 넣어 클래스를 만듦
    • 직접 인스턴스화 될 수 없는 클래스임
  • 대신 직접 인스턴스화 될 수 없지만 extends 하여 파생 클래스를 인스턴스화 할 수 있음
  • 추상 클래스는 구현된 메서드를 포함시킬 수 있음
  • abstract를 선언한 메서드는 파생된 클래스에서 메서드를 꼭 구현되어야 함
    • 선언된 메서드 :
      hello(){}, 말그대로 선언만 되어있는 상태, 내부는 만들어져 있지 않음
    • 구현된 메서드 :
      hello(){console.log('hi');}, 선언 + 구현이 되어있는 상태
abstract class Animal {
  // 선언된 메서드
  abstract hello(): string
  
  // 구현된 메서드
  run() {
    return this.hello() + ' run';
  }
}

const animal = new Animal(); // error, 직접 인스턴스화 될 수 없음

class Person extends Animal {
  hello() {
    return 'Person';
  }
}

const person = new Person();  // extends 후 파생 클래스 인스턴스화 가능
console.log(person.hello());  // Person

Parameter Properties

  • 필드를 만들고 생성자 매개변수를 거의 동일하게 또 만드는 과정이 귀찮음
    => 때문에 접근 제어자 필드를 한번에 생성자 매개변수로 전달
class Person {
  public name: string;
  private age: number;
  
  constructor (name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  
  /* ↑ 같은 거 ↓, Parameter Properties ↓ */
  constructor (
    public name: string,    
    private age: number
  ) {}
}

오버로딩(Overloading), 오버라이딩(Overriding)

오버로딩(Overloading)

  • 메서드의 이름은 같고 매개변수의 갯수나 타입이 다른 함수를 정의하는 것
  • 리턴값만을 다르게 갖는 오버로딩은 작성 할 수 없음
class Animal {
  run() {
    return 'Animal이 달린다'
  }
  run(a) {
    return `${a}가 달린다`
  }
}

const a = new Animal();

console.log(a.run());  // Animal이 달린다
console.log(a.run('YEZI'));  // YEZI가 달린다

오버라이딩(Overriding)

  • 상위 클래스의 메서드를 하위 클래스가 재정의 하는 것
class Animal {
  run() {
    return 'Animal이 달린다'
  }
}
class Person extends Animal {
  run() {
    return 'Person이 달린다'
  }
}
class Dog extends Animal {
  run() {
    return 'Dog 달린다'
  }
}

const a = new Animal();
const p = new Person();
const d = new Dog();

console.log(a.run());  // Animal이 달린다
console.log(p.run());  // Person이 달린다
console.log(d.run());  // Dog 달린다
profile
까먹지마도토도토잠보🐘

0개의 댓글