TypeScript

๐Ÿ“— Classes

yunieyunie 2022. 12. 19. 11:35

๐Ÿ“‘ Classes

Classes๋ž€ object(๊ฐ์ฒด)๋ฅผ ๋งŒ๋“œ๋Š” blueprint (์ฒญ์‚ฌ์ง„, ์„ค๊ณ„๋„)๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.
ํด๋ž˜์Šค ์ด์ „์— object๋ฅผ ๋งŒ๋“œ๋Š” ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ•์€ function์ด๋‹ค.
JavaScript์—๋„ class๋Š” es6 ๋ถ€ํ„ฐ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ ‘๊ทผ์ œ์–ด์ž ๊ฐ™์€ ๋ช‡๊ฐ€์ง€ ๊ธฐ๋Šฅ์ด ๋ถ€์กฑํ•˜๋‹ค.
typescript์—์„œ OOP์„ ์œ„ํ•œ ์ดˆ์„์œผ๋กœ class์˜ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.
๋˜ํ•œ TypeScript ์—์„œ๋Š” ํด๋ž˜์Šค๋„ ์‚ฌ์šฉ์ž๊ฐ€ ๋งŒ๋“œ๋Š” ํƒ€์ž… ์ค‘์˜ ํ•˜๋‚˜๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

class Person {}
  const p1 = new Person(); 
  console.log(p1);
class Person { 
        name;
      constructor(name: string) { 
          this.name = name;
    } 
  }
  const p1 = new Person('Mark'); 
  console.log(p1);
  • class ํ‚ค์›Œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  class ์ด๋ฆ„์€ ๋ณดํ†ต ๋Œ€๋ฌธ์ž๋ฅผ ์ด์šฉํ•œ๋‹ค.
  • ๋˜ํ•œ new ๋ฅผ ์ด์šฉํ•˜์—ฌ class ๋ฅผ ํ†ตํ•ด object ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ณ  constructor ๋ฅผ ์ด์šฉํ•˜์—ฌ object ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด์„œ ๊ฐ’์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • this ๋ฅผ ์ด์šฉํ•ด์„œ ๋งŒ๋“ค์–ด์ง„ object ๋ฅผ ๊ฐ€๋ฆฌํ‚ฌ ์ˆ˜ ์žˆ๊ณ  JS ๋กœ ์ปดํŒŒ์ผ๋˜๋ฉด es5 ์˜ ๊ฒฝ์šฐ function ์œผ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.

๐ŸŽˆ constructor & initialize

// strict : true 
  class Person {
    name: string = "Mark"; //์ดˆ๊ธฐ๊ฐ’ ์„ค์ • ๋ฐฉ๋ฒ•1
    age: number; 

    constructor(age: number) { //์ดˆ๊ธฐ๊ฐ’ ์„ค์ • ๋ฐฉ๋ฒ•2
        this.age = age;
    }  
  }

  const p1: Person = new Person(20); 
  console.log(p1); // Person1 {}
  console.log(person.age); // 20
  • ์ƒ์„ฑ์ž ํ•จ์ˆ˜๊ฐ€ ์—†์œผ๋ฉด, ๋””ํดํŠธ ์ƒ์„ฑ์ž๊ฐ€ ๋ถˆ๋ฆฌ๊ณ  ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ๋งŒ๋“  ์ƒ์„ฑ์ž๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด, ๋””ํดํŠธ ์ƒ์„ฑ์ž๋Š” ์‚ฌ๋ผ์ง„๋‹ค.
  • strict ๋ชจ๋“œ์—์„œ๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ ์–ธํ•˜๋Š” ๊ณณ ๋˜๋Š” ์ƒ์„ฑ์ž์—์„œ ๊ฐ’์„ ํ• ๋‹นํ•ด์•ผ ํ•œ๋‹ค.
  • ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ ์–ธํ•˜๋Š” ๊ณณ ๋˜๋Š” ์ƒ์„ฑ์ž์—์„œ ๊ฐ’์„ ํ• ๋‹นํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋Š” ! ๋ฅผ ๋ถ™์—ฌ์„œ ์œ„ํ—˜์„ ํ‘œํ˜„ํ•œ๋‹ค.
  • ํด๋ž˜์Šค์˜ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์ง€๋งŒ, ๊ฐ’์„ ๋Œ€์ž…ํ•˜์ง€ ์•Š์œผ๋ฉด undefined ์ด๋‹ค.
  • ์ƒ์„ฑ์ž์—๋Š” async ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์—†๋‹ค.

โ›” ์ ‘๊ทผ ์ œ์–ด์ž (Access Modifiers)

class Person {
    public name: string = "Mark"; 
    private _age: number; 

    public constructor(age: number) { 
        this.age = age;
    }  
  }

  const p1: Person = new Person(20); 
  console.log(p1); // p1.age ์ ‘๊ทผ ๋ถˆ๊ฐ€
  
  • ์ ‘๊ทผ ์ œ์–ด์ž์—๋Š” public, private, protected ๊ฐ€ ์žˆ๊ณ  ์„ค์ •ํ•˜์ง€ ์•Š์œผ๋ฉด public ์ด๋‹ค.
  • ํด๋ž˜์Šค ๋‚ด๋ถ€์˜ ๋ชจ๋“  ๊ณณ์— (์ƒ์„ฑ์ž, ํ”„๋กœํผํ‹ฐ, ๋ฉ”์„œ๋“œ) ์„ค์ • ๊ฐ€๋Šฅํ•˜๋‹ค.
  • private ์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ํด๋ž˜์Šค ์™ธ๋ถ€์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค.
  • protected๋Š” ์™ธ๋ถ€์—์„œ๋Š” ์ ‘๊ทผ์ด ๋ถˆ๊ฐ€ํ•˜์ง€๋งŒ ์ƒ์†๊ด€๊ณ„์—์„œ๋Š” ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ private ์ง€์›ํ•˜์ง€ ์•Š์•„ ์˜ค๋žซ๋™์•ˆ ํ”„๋กœํผํ‹ฐ๋‚˜ ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ์•ž์— _ ๋ฅผ ๋ถ™์—ฌ์„œ ํ‘œํ˜„ํ–ˆ๋‹ค.

๐Ÿ’จ initialization in constructor parameters

์ƒ์„ฑ์ž์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›์•„์„œ ๋ฐ”๋กœ ํด๋ž˜์Šค์˜ ํ”„๋กœํผํ‹ฐ๋กœ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

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

  const p1: Person = new Person({"Mark", 20); 
  console.log(p1); // p1.age ์ ‘๊ทผ ๋ถˆ๊ฐ€

๐Ÿ– Getters & Setters

๊ฐ’์„ ๋ฐ›์•„์˜ค๋Š” ๊ฒƒ์„ get, ๊ฐ’์„ ์ƒˆ๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์„ set์ด๋ผ๊ณ  ํ•œ๋‹ค.

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

  const p1: Person = new Person({"Mark", 20); 
  console.log(p1); // get
  p1.name = "yuni" //set

๊ฐ’์„ ๋ฐ›์•„์˜ค๋Š” get์„ ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ getter, ๊ฐ’์„ ์ƒˆ๋กœ ์„ค์ •ํ•˜๋Š” set์„ ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ setter ๋ผ๊ณ  ํ•œ๋‹ค.
get๊ณผ set์€ ๊ฐ™์ด ์„ค์ •๋˜์–ด์•ผ ํ•œ๋‹ค.

class Person {
     public constructor(public _name: string, private age: number) {}

     get name() {
          return this._name + "kim"; 
     }

     set name(n: string) {
             this._name = n;
     }
  }


  const p1: Person = new Person({"Mark", 20); 
  console.log(p1.name); // Mark kim
  p1.name = "yuni" //
  console.log(p1.name) // yuni kim

๐Ÿ“› readonly properties

readonly๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ดˆ๊ธฐํ™”๋˜๋Š” ์˜์—ญ์—์„œ๋งŒ ๊ฐ’์„ ์„ธํŒ…ํ•  ์ˆ˜ ์žˆ๊ณ  ๋‹ค๋ฅธ ๊ณณ์—์„  ๋ฐ”๊ฟ€ ์ˆ˜ ์—†๋‹ค.
๋”ฐ๋ผ์„œ ์ดˆ๊ธฐ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์ง€ ์•Š์„ ๋•Œ readonly๋ฅผ ๋ถ™์ด๋ฉด ๋œ๋‹ค.

class Person {
      public readonly name: string = "Mark";
      private readonly country: string;

         public constructor(public _name: string, private age: number) {
          this.county = "Korea";
      }

      hello() {
          this.country = "China"; //readonly๊ฐ€ ์žˆ์–ด์„œ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€
      }
  }


  const p1: Person = new Person({"Mark", 20); 
  p1.name = "yuni" //readonly๊ฐ€ ์žˆ์–ด์„œ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€

โžฐ Index Signatures in class

์›๋ž˜ ํด๋ž˜์Šค ์•ˆ์—์„œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ ์–ธํ•˜๋ฉด ํ•ญ์ƒ ์ดˆ๊ธฐํ™”๋ฅผ ํ•ด์คฌ์–ด์•ผ ํ•˜๋Š”๋ฐ Index Signatures๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ์„ ์ˆ˜๋„ ์—†์„ ์ˆ˜๋„ ์žˆ๋Š” ๋™์ ์ธ ๊ฒฝ์šฐ์— ์œ ์šฉํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋‹ค.

class Student {
      [index: string]: "male" | "female";
  }

  const a = new Students();
  a.mark = "male";
  a.jade = "male";

  const b = new Students();
  b.chloe = "female";
  b.alex = "male";

  console.log(a); //Students { mark: 'male', jade: 'male'}
  console.log(b); //Students { chloe: 'female', alex: 'male', anna: 'female'}

โญ• Static Properties & Methods

๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ๋‹ค๋ฉด ์•ž์— static์„ ๋ถ™์ด๋ฉด ๋œ๋‹ค.

class Person {
      public hello() {
          console.log('์•ˆ๋…•');
      }
  }

  const p1 = new Person();
  p1.hello();

  //static์„ ๋ถ™์ด๋ฉด 
  class Person {
      public static hello() {
          console.log('์•ˆ๋…•');
      }
  }

  const p1 = new Person();
  p1.hello(); //์—๋Ÿฌ
  Person.hello();
  

static์ด ๋ถ™์€ ํ•จ์ˆ˜๋Š” ํ•จ์ˆ˜๋กœ ์ƒ๊ฐํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ p1.hello()๋กœ๋Š” ์ ‘๊ทผ ๋ถˆ๊ฐ€ํ•˜๋‹ค.

class Person {
      private static CITY = "Seoul";
      public hello() {
          console.log('์•ˆ๋…•', Person.CITY);
      }
      public change() {
          person.CITY = "LA";
      }
  }

  const p1 = new Person();
  p1.hello(); //์•ˆ๋…• Seoul

  const p2 = new Person();
  p2.hello(); //์•ˆ๋…• Seoul

  p1.change(); 
  p2.hello(); //์•ˆ๋…• LA
  

1๏ธโƒฃ Singletons

Singletons pattern์ด๋ž€ ์–ดํ”Œ์ด ์‹คํ–‰๋˜๋Š” ์ค‘๊ฐ„์— ํด๋ž˜์Šค๋กœ๋ถ€ํ„ฐ ๋‹จ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋งŒ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

class ClassName {

  const a = new ClassName();
  const b = new ClassName();

๋จผ์ € new๋กœ ํด๋ž˜์Šค ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ๋ง‰์•„๋ณด์ž.

class ClassName {
      private constructor(){}
  }

  const a = new ClassName();
  const b = new ClassName();

์ด๋ฒˆ์—๋Š” ๋‹ค๋ฅธ ๋งค๊ฐœ์ฒด๋ฅผ ์ด์šฉํ•ด ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋ฅผ ๋‹ฌ๋ผ๊ณ  ํ•˜์—ฌ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

class ClassName {
      private static instance = ClassName | null = null;
      public static getInstance(): ClassName {

          //ClassName์œผ๋กœ ๋ถ€ํ„ฐ ๋งŒ๋“  ๊ฐ์ฒด๊ฐ€ ์žˆ์œผ๋ฉด ๋ฆฌํ„ด, ์—†์œผ๋ฉด ๋งŒ๋“ค์–ด์„œ ๋ฆฌํ„ด
          if (ClassName.instance === null){
              ClassName.instance = new ClassName();
          }    
          return ClassName.Instance;
      }

      private constructor(){}
  }

  const a = ClassName.getInstance();
  const b = ClassName.getInstance();

  console.log(a === b); //true

๐Ÿ‘ช ์ƒ์† (Inheritance)

ํด๋ž˜์Šค๊ฐ€ ๋‹ค๋ฅธ ํด๋ž˜์Šค๋ฅผ ๊ฐ€์ ธ๋‹ค๊ฐ€ ์ž์‹ ๋งŒ์˜ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ƒ์†์ด๋‹ค.
๋ถ€๋ชจ ํด๋ž˜์Šค์ธ Parent๋ฅผ ์ƒ์†๋ฐ›์€ ์ž์‹ ํด๋ž˜์Šค Child๋Š” ์ƒ์„ฑ์ž๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ›์•„์˜ค๊ฒŒ ๋œ๋‹ค.

//๋ถ€๋ชจ ํด๋ž˜์Šค
  class Parent {
      constructor(protected _name: string, private _age: number) {}

      public print(): void {
          console.log(`์ด๋ฆ„์€ ${this._name}์ด๊ณ  ๋‚˜์ด๋Š” ${this._age}์ž…๋‹ˆ๋‹ค`);
      }
  }

  const p = new Parent("yuni", 27);
  p.print();//์ด๋ฆ„์€ yuni์ด๊ณ  ๋‚˜์ด๋Š” 27์ž…๋‹ˆ๋‹ค

๋ถ€๋ชจ ํด๋ž˜์Šค์—์„œ ์ •์˜๋œ ๊ฒƒ์„ ์ž์‹ ํด๋ž˜์Šค์—์„œ ์žฌ์ •์˜ ํ•˜๋Š” ๊ฒƒ์ด ์˜ค๋ฒ„๋ผ์ด๋”ฉ์ด๋‹ค.

//์ƒ์†
  class Child extends Parent {
      //์˜ค๋ฒ„๋ผ์ด๋”ฉ
      // public _name = "mark";

      //์ƒˆ๋กœ ์ถ”๊ฐ€
      public gender = 'male';

      //์˜ค๋ฒ„๋ผ์ด๋”ฉ
      constructor(age: number) {
          //super๋กœ ๋ถ€๋ชจ ์ƒ์„ฑ์ž ํ˜ธ์ถœ
          super('mark',age);
      }

  }
  const c = new Child(2);
  c.print();//์ด๋ฆ„์€ mark์ด๊ณ  ๋‚˜์ด๋Š” 2์ž…๋‹ˆ๋‹ค

๋ถ€๋ชจ ํด๋ž˜์Šค์— ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด super๊ฐ€ ๋จผ์ €์˜ค๊ณ  ๊ทธ ๋‹ค์Œ์— this.ํ•จ์ˆ˜๊ฐ€ ์™€์•ผ ํ•จ์— ์ฃผ์˜ํ•˜์ž.

class Parent {
      constructor(protected _name: string, private _age: number) {}

      public print(): void {
          console.log(`์ด๋ฆ„์€ ${this._name}์ด๊ณ  ๋‚˜์ด๋Š” ${this._age}์ž…๋‹ˆ๋‹ค`);
      }

      protected printName(): void {
          console.log(this._name); //mark
      }
  }

  //์ƒ์†
  class Child extends Parent {

      //์˜ค๋ฒ„๋ผ์ด๋”ฉ
      constructor(age: number) {
          super('mark',age);
          this.printName();
      }

  }
  const c = new Child(2);
  c.print(); //์ด๋ฆ„์€ mark์ด๊ณ  ๋‚˜์ด๋Š” 2์ž…๋‹ˆ๋‹ค

โ“ Abstract Classes

Abstract๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์™„์ „ํ•˜์ง€ ์•Š์€ ํด๋ž˜์Šค๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
ํด๋ž˜์Šค ์ด๋ฆ„ ๋งจ ์•ž์— abstract๋ฅผ ๋ถ™์ด๋ฉด ๊ทธ ํด๋ž˜์Šค ์•ˆ์— ์žˆ๋Š” ๊ธฐ๋Šฅ์ด ์™„์ „ํ•˜์ง€ ์•Š์•„๋„ ๋˜๋ฉฐ ๊ทธ ๊ธฐ๋Šฅ ์•ž์—๋„ abstract๋ฅผ ๋ถ™์—ฌ์ฃผ๋ฉด ๋œ๋‹ค.

abstract class AbstractPerson {
      protected _name: string = 'yuni';

      abstract setName(name: string): void;
  }

  new AbstractPerson(); //abstract๋ผ์„œ ๋ถˆ๊ฐ€

abstract ํด๋ž˜์Šค๋Š” ๊ธฐ๋Šฅ์ด ์™„์ „ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— new๋ฅผ ํ•  ์ˆ˜ ์—†๋‹ค.
์ƒ์†์„ ํ†ตํ•ด ์˜ค๋ฒ„๋ผ์ด๋”ฉ์œผ๋กœ abstractํด๋ž˜์Šค๋ฅผ ์™„์ „ํ•˜๊ฒŒ ๋งŒ๋“  ํ›„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

abstract class AbstractPerson {
      protected _name: string = 'yuni';

      abstract setName(name: string): void;
  }

  new AbstractPerson(); //abstract๋ผ์„œ ๋ถˆ๊ฐ€

  //์ƒ์†
  class Person extends AbstractPerson {
      setName(name: string): void {
          this._name = name;
      }
  }

  const p = new Person();
  p.setName();