ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Typescript] Class
    Language/Typescript 2023. 1. 11. 21:51
    ๐Ÿ“Œ ์ฐธ๊ณ  : https://poiemaweb.com/typescript-class

    ๊ธฐ๋ณธ๋ฌธ๋ฒ•

    ES6 ํด๋ž˜์Šค๋Š” ํด๋ž˜์Šค ๋‚ด๋ถ€์— ๋ฉ”์†Œ๋“œ๋งŒ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰ ๋ฉค๋ฒ„๋ณ€์ˆ˜(ํ”„๋กœํผํ‹ฐ) ์„ ์–ธ์€ ๋ถˆ๊ฐ€ํ•˜๊ณ , ๋ฉค๋ฒ„ํ•จ์ˆ˜(๋ฉ”์†Œ๋“œ)๋งŒ ์„ ์–ธ ๊ฐ€๋Šฅํ•˜๋‹ค.

    ๋ฉค๋ฒ„๋ณ€์ˆ˜์˜ ์„ ์–ธ์€ ๋ฐ˜๋“œ์‹œ ์ƒ์„ฑ์ž ๋‚ด๋ถ€์—์„œ ํด๋ž˜์Šค ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ ์–ธํ•˜๊ณ  ์ดˆ๊ธฐํ™” ํ•œ๋‹ค.

    // person.js
    class Person {
    	constructor(name) {
    	this.name = name
    	}
    
    	walk() {
    		console.log(`${this.name} is walking.`)
    	}
    }

    ํ•˜์ง€๋งŒ Typescript ํด๋ž˜์Šค๋Š” ํด๋ž˜์Šค ๋ชธ์ฒด(๋‚ด๋ถ€)์— ํด๋ž˜์Šค ํ”„๋กœํผํ‹ฐ์˜ ํƒ€์ž…์„ ์‚ฌ์ „ ์„ ์–ธํ•˜์—ฌ์•ผ ํ•œ๋‹ค.

    //person.ts
    class Person {
    	name : string;
    
    	constructor(name:string) {
    		this.name = name;
    	}
    	
    	walk() {
    		console.log(`${this.name} is walking.`)
    	}
    }
    const person = new Person('Lee');
    person.walk(); // Lee is walking
    

     

    ์ ‘๊ทผ์ œํ•œ์ž

    public, private, protected๋ฅผ ์ง€์›ํ•œ๋‹ค.

    ๋ณดํ†ต ๋‹ค๋ฅธ ๊ฐ์ฒด์ง€ํ–ฅ ์–ธ์–ด๋Š” ํด๋ž˜์Šค์˜ ํ”„๋กœํผํ‹ฐ์™€ ๋ฉ”์†Œ๋“œ์— ์ ‘๊ทผ์ œํ•œ์ž๋ฅผ ์ƒ๋žตํ•˜๋ฉด, ์•”๋ฌต์ ์œผ๋กœ protected ์ธ๋ฐ

    typescript๋Š” public์ด ์•”๋ฌต์ ์œผ๋กœ ์„ ์–ธ๋œ๋‹ค.

     

    ๋ฐ˜๋ฉด, ์ƒ์„ฑ์ž ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ ‘๊ทผ์ œํ•œ์ž๋ฅผ ์ƒ๋žตํ•˜๋ฉด ์ƒ์„ฑ์ž ๋‚ด๋ถ€์—์„œ๋งŒ ์œ ํšจํ•œ ์ง€์—ญ๋ณ€์ˆ˜๊ฐ€ ๋˜์–ด ์ƒ์„ฑ์ž ์™ธ๋ถ€์—์„œ ์ฐธ์กฐ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

    ์ ‘๊ทผ ์ œํ•œ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ? ์บก์Šํ™”(encapsulation)!!

     

    • ์ ‘๊ทผ์ œํ•œ์ž ๋ณ„ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์œ„์น˜
    ๐Ÿ“Œ ์ถœ์ฒ˜ : https://velog.io/@mollog/Class-Public-Private-field-MDN-๋‚ด์šฉ-์ •๋ฆฌ
    ๊ตฌ๋ถ„  public  protected  private
    ํด๋ž˜์Šค ๋‚ด๋ถ€ O O O
    ์ž์‹ ํด๋ž˜์Šค ๋‚ด๋ถ€ O O X
    ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค O X X

     

    • ์ƒ์„ฑ์ž ํŒŒ๋ผ๋ฏธํ„ฐ(๋ฉค๋ฒ„๋ณ€์ˆ˜)์—์„œ ์ ‘๊ทผ ์ œํ•œ์ž ์„ ์–ธ

    ์ƒ์„ฑ์ž ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ ‘๊ทผ ์ œํ•œ์ž๋ฅผ ์„ ์–ธํ•˜๋Š” ๊ฒฝ์šฐ, ํ•ด๋‹น ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์•”๋ฌต์ ์œผ๋กœ ํด๋ž˜์Šค ํ”„๋กœํผํ‹ฐ(๋ฉค๋ฒ„๋ณ€์ˆ˜)๋กœ ์„ ์–ธ๋˜๊ณ 

    ์ƒ์„ฑ์ž ๋‚ด๋ถ€์—์„œ ๋ณ„๋„์˜ ์ดˆ๊ธฐํ™”(this.parameter)๋ฅผ ํ•˜์ง€ ์•Š์•„๋„ ์•”๋ฌต์ ์œผ๋กœ ์ดˆ๊ธฐํ™”๊ฐ€ ์ˆ˜ํ–‰๋œ๋‹ค.

    ์ด๋•Œ, ๋งŒ์•ฝ ์ƒ์„ฑ์ž ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ ‘๊ทผ์ œํ•œ์ž๊ฐ€ ์„ ์–ธ๋˜์ง€ ์•Š์œผ๋ฉด,

    ํ•ด๋‹น ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ์ƒ์„ฑ์ž ๋‚ด๋ถ€์—์„œ๋งŒ ์œ ํšจํ•œ ์ง€์—ญ๋ฒˆ์ˆ˜๊ฐ€ ๋˜์–ด ์ƒ์„ฑ์ž ์™ธ๋ถ€์—์„œ ์ฐธ์กฐ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋œ๋‹ค.

    // In Typescript
    class Player {
      constructor(
        private firstName: string,
        private lastName: string,
        public nickname: string,
    		score : number
      ) {}
    }
    
    // Compile to Javascript
    class Player {
        constructor(firstName, lastName, nickname, score) {
            this.firstName = firstName;
            this.lastName = lastName;
            this.nickname = nickname;
        }
    }
    
    const goodPlayer = new Player('๋ช…์„', '์ด', '๋น›๋Œ', 100);
    
    goodPlayer.firstName = "๋ช…์„๋ช…์„" // error : 'firstName' ์†์„ฑ์€ private์ด๋ฉฐ 'Player' ํด๋ž˜์Šค ๋‚ด์—์„œ๋งŒ ์—‘์„ธ์Šค ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    goodPlayer.nickname = "๋ฐ”๋ณด"
    goodPlayer.score = undefined
    

     

    • readonly ํ‚ค์›Œ๋“œ
    ์ถœ์ฒ˜ : http://typescriptstudy.com/ts/article/14-%ED%81%B4%EB%9E%98%EC%8A%A4-class

    readonly๊ฐ€ ์„ ์–ธ๋œ ํด๋ž˜์Šค ํ”„๋กœํผํ‹ฐ๋Š” ์„ ์–ธ ์‹œ ๋˜๋Š” ์ƒ์„ฑ์ž ๋‚ด๋ถ€์—์„œ๋งŒ ๊ฐ’์„ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ ์™ธ์˜ ๊ฒฝ์šฐ์—๋Š” ๊ฐ’์„ ํ• ๋‹นํ•  ์ˆ˜ ์—†๊ณ  ์˜ค์ง ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ƒ์ˆ˜์˜ ์„ ์–ธ ์‹œ ์‚ฌ์šฉํ•œ๋‹ค.

     
    class Employee {
        // ์ƒ์„ฑ์ž์—์„œ id ์ง€์ •ํ•œ ํ›„ ์ฝ๊ธฐ ์ „์šฉ
        readonly id: number;   
        dept: string;
    
        constructor(empId: number) {
            this.id = empId;
        }
    
        // ์†์„ฑ ์„ ์–ธ์‹œ ๊ฐ’ ์ง€์ •
        readonly empType: string = "FTE";
    }

     

    • static ํ‚ค์›Œ๋“œ
    ์ถœ์ฒ˜ : http://typescriptstudy.com/ts/article/14-%ED%81%B4%EB%9E%98%EC%8A%A4-class

    ํด๋ž˜์Šค์˜ ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค. ์ฆ‰ 'this.ํ”„๋กœํผํ‹ฐ๋ช…"์„ ํ†ตํ—ค ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋‹ค. ํ•˜์ง€๋งŒ ํด๋ž˜์Šค ํ”„๋กœํผํ‹ฐ์— static ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๋ฉด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๋”๋ผ๋„ "ํด๋ž˜์Šค๋ช….ํ”„๋กœํผํ‹ฐ๋ช…"์œผ๋กœ ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค. ์ฆ‰ static ํ‚ค์›Œ๋“œ๋Š” ์ •์  ํ”„๋กœํผํ‹ฐ๋ฅผ ๋งŒ๋“œ๋Š” ํ‚ค์›Œ๋“œ์ด๋‹ค.

    class Exam {    
        static Cutline: number = 80;
     
        scoreCheck(score: number) {
            if (score >= Exam.Cutline) {
                console.log("PASS");
            }
            else {
                console.log("FAIL");
            }
        }
    }
     
    let exam: Exam;
    exam = new Exam();
    console.log("cutline: " + Exam.Cutline);
    exam.scoreCheck(85);

     

    ์ถ”์ƒํด๋ž˜์Šค

    ๋‹ค๋ฅธ ํด๋ž˜์Šค๊ฐ€ ์ƒ์†๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ํด๋ž˜์Šค.

    ํ•˜์ง€๋งŒ ์ถ”์ƒ ํด๋ž˜์Šค๋กœ๋Š” ์ง์ ‘ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†๋‹ค.

    abstract class User {
      constructor(
        private firstName: string,
        private lastName: string,
        public nickname: string
      ) {}
    }
    
    class Player extends User {}
    
    const nico = new User('nico', 'las', '๋‹ˆ๊ผฌ');/ // ์ถ”์ƒ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

     

    ์ถ”์ƒ๋ฉ”์†Œ๋“œ

    ์ถ”์ƒ๋ฉ”์†Œ๋“œ๋Š” ์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›๋Š” ํด๋ž˜์Šค๊ฐ€ ๊ตฌํ˜„(implement)์„ ํ•ด์•ผํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

    ์ถ”์ƒ๋ฉ”์†Œ๋“œ๋Š” ์ธ์ž๋ฅผ ์ •์˜ํ•ด์„œ๋Š” ์•ˆ๋˜๊ณ , call signatuer๋งŒ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค.

    abstract class User {
      constructor(
        private firstName: string,
        private lastName: string,
        public nickname: string
      ) {}
      abstract getNickName(): void;
      getFullName() {
        return `${this.firstName} ${this.lastName}`;
      }
    }
    
    class Player extends User {} //๋น„์ถ”์ƒ ํด๋ž˜์Šค 'Player'๋Š” 'User' ํด๋ž˜์Šค์—์„œ ์ƒ์†๋œ ์ถ”์ƒ ๋ฉค๋ฒ„(๋ฉ”์†Œ๋“œ) ' getNickName'์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
    
    const nico = new Player('nico', 'las', '๋‹ˆ๊ผฌ');
    

     

    Interface

    ๊ฐ์ฒด์˜ ํƒ€์ž…์„ ํŠน์ •ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

    type ํ‚ค์›Œ๋“œ๋กœ๋„ ๊ฐ์ฒด์˜ ํƒ€์ž…์„ ์ •ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ฐ์ฒด์˜ ๋ชจ์–‘์„ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ inteface๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์˜๋„์— ๋งž๋Š” ํ™œ์šฉ์ผ ์ˆ˜ ์žˆ๋‹ค.

    ๊ทธ๋ฆฌ๊ณ  inteface๋Š” ๊ฐ™์€ ์ด๋ฆ„์„ ๊ฐ€์ง„ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋˜ ์„ ์–ธ(์„ ์–ธ ๋ณ‘ํ•ฉ)ํ•˜์—ฌ ๊ธฐ์กด์˜ ์ธํ„ฐํŽ˜์ด์Šค ํƒ€์ž…์— ์ƒˆ๋กœ์šด ํƒ€์ž…์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ

    typeํ‚ค์›Œ๋“œ๋Š” ๊ฐ™์€ ์ด๋ฆ„์„ ๊ฐ€์ง„ ํƒ€์ž…์„ ๋‹ค์‹œ ์„ ์–ธํ•  ์ˆ˜ ์—†๋‹ค.

    ๋˜ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋Š” ํด๋ž˜์Šค์ฒ˜๋Ÿผ ๋‹ค๋ฅธ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†ํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    ์ด์™€๋Š” ๋ฐ˜๋Œ€๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™œ์šฉํ•˜๊ธฐ๋ณด๋‹ค, type alias๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ์œ ์šฉํ•˜๋‹ค๋Š” ์˜๊ฒฌ๋„ ์žˆ๋‹ค.

    1. ํ•จ์ˆ˜์˜ type์„ ๋‚˜ํƒ€๋‚ด๋Š”๋ฐ ๋” ์ง๊ด€์ ์ด๋‹ค.
    2. IDE์—์„œ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ๋” ์ž˜ ์ง€์›ํ•œ๋‹ค.
    -> ์ธํ„ฐํŽ˜์ด์Šค๋Š” call signature๋ฅผ ๋ฐ”๋กœ ํ™•์ธํ•  ์ˆ˜ ์—†์ง€๋งŒ, type alias๋Š” ๋งˆ์šฐ์Šค ์ปค์„œ๋ฅผ ๊ฐ€์ ธ๋‹ค ๋Œ€๋ฉด ๋ฐ”๋กœ ํ™•์ธ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    3. ์›์น˜ ์•Š๋Š” ์„ ์–ธ ๋ณ‘ํ•ฉ์„ ๋ง‰์•„์ค€๋‹ค.
    ์ถœ์ฒ˜ : https://techblog.woowahan.com/9804/

     

    interface Person {
      firstName: string;
      lastName: string;
    }
    // concrete type
    type Team = "red" | "blue" | "yellow" 
    type Health = 1 | 5 | 10
    
    // we can use interface
    // interface is only used to make object type
    // but, type is used in many purposes
    // Player === Person
    type Player = {
      nickname :string
      team : Team
      health :Health
    }
    interface Person {
      nickname :string
      team : Team
      health :Health
    }
    
    interface User {
      name: string
    }
    
    // interface is similar to class
    interface Player extends User {
    }
    
    const nico : Player = {
      name :"nico"
    }
    
    // we can do this to use type keyword like this
    type User = {
      name:string
    }
    
    type Player = User & {
    }
    
    const nico : Player = {
      name : 'nico'
    }
    
    // // but, When define object shape, inteface is better
    
    interface User {
      name:String
    }
    
    interface User {
      lastName : string
    }
    
    interface User {
      health: number
    }
    
    const nico : User = {
      name:'nico',
      lastName:'las',
      health:1
    }
    
    //also, interface can combine type in same interface params
    
    // type extends
    type PlayerA = {
      name :string
    }
    
    type PlayerAA = PlayerA & {
      lastName : string
    }
    
    type PlayerAAA = 
    
    const playerA : PlayerAA = {
      name:'nico',
      lastName :'xxx'
    }
    
    //----------------------//
    
    interface PlayerB {
      name:string
    }
    
    interface PlayerBB extends PlayerB {
      lastName:string
    }
    // or
    // interface PlayerB {
    //   lastName:string
    // }
    
    const playerB : PlayerB = {
      name:'nico',
      lastName : 'yyy'
    }

     

    ์ธํ„ฐํŽ˜์ด์Šค์™€ ์ถ”์ƒํด๋ž˜์Šค์˜ ์ฐจ์ด

    ์ถ”์ƒํด๋ž˜์Šค๋Š” ๋‹จ์ˆœํžˆ ํ‘œ์ค€ํ™”๋œ ํ”„๋กœํผํ‹ฐ์™€ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ–๋„๋กํ•˜๋Š” ์ฒญ์‚ฌ์ง„ ์—ญํ• ์„ ํ•˜๋Š”๋ฐ

    ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ปดํŒŒ์ผํ•˜๋ฉด ๋‹จ์ˆœ ํด๋ž˜์Šค๋กœ ๋ณ€ํ•œ๋‹ค.

    ๋งŒ์•ฝ ์ถ”์ƒํด๋ž˜์Šค๊ฐ€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋กœ ํด๋ž˜์Šค๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒƒ์ด ์˜๋ฏธ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
    ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๊ฐ€๋ณ๊ธฐ ๋•Œ๋ฌธ์— ์ปดํŒŒ์ผํ•˜๋ฉด JS๋กœ ๋ฐ”๋€Œ์ง€ ์•Š๊ณ  ์‚ฌ๋ผ์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    ๋‹จ, ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์ ‘๊ทผ์ œํ•œ์ž(protected, private)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

    abstract class User {
      constructor(
        protected firstName :string,
        protected lastName :string
      ) {}
      abstract sayHi(name:string):string
      abstract fullName():string
    }
    
    class Player extends User {
      fullName () {
        return `${this.firstName} ${this.lastName}`
      }
      sayHi (name:string) {
        return `Hello ${name}. My name is ${this.fullName()}`
      }
    }
    
    // abstract class can't make instance.
    // abstract class is just blueprint!!
    // ๊ทธ๋ ‡๋‹ค๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์“ธ ๋•Œ ํด๋ž˜์Šค๊ฐ€ ํŠน์ • ํ˜•ํƒœ๋ฅผ ๋”ฐ๋ฅด๋„๋ก ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„๊นŒ?
    
    interface User {
      firstName :string
      lastName :string
      sayHi(name:string):string
      fullName():string
    }
    
    interface Human {
      health : number
    }
    
    // implements!!
    // but when implements interface, we can't set properties private, protected
    class Player implements User, Human {
      constructor(
        readonly firstName:string,
        readonly lastName:string,
        health : number
        ){}
        fullName () {
          return `${this.firstName} ${this.lastName}`
          }
        sayHi (name:string) {
          return `Hello ${name}. My name is ${this.fullName()}`
          }
    }
    
    // interface and type both replace abstract class
    type PlayerA = {
      firstName:string
    }
    
    interface PlayerB {
      firstName:string
    }
    
    class User implements PlayerB {
      constructor (
        public firstName:string
      ){}
    }

     

    ๋Œ“๊ธ€