ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [TS] 클래스
    codeStates front-end/Typescript 2023. 3. 20. 21:26
    반응형

    목차

       

       

       

       

      📌  클래스

       

       

       

      📍클래스

       

      타입스크립트는 자바스크립트와 동일하게 클래스를 선언하고 사용할 수 있다.

      클래스란? 여러 객체들을 생성하기 위한 탬플릿 (EX) 클래스 : 붕어빵 기계, 객체 : 붕어빵)

      클래스의 핵심 기능은 상속!!!! 👉🏼👉🏼 효율적이고 유지보수가 편함

       

      빈 클래스를 생성해서 새로운 프로퍼티를 선언

       

      class Site {
        no: number = 0;
      }

       

      🔗  클래스 메서드

      클래스는 기본적으로 속성메서드를 갖는다.

      클래스에서 매게변수 타입에 타입이나 기본값을 지정하지 않으면 any

      메서드를 호출하려면 허용 가능한 수의 인수가 필요하고, 재귀함수가 아니라면 대부분 반환타입 유추 가능

       

      빈 프로퍼티 아래에 메소드를 추가

       

      class Site {
        no: number;
      
        constructor(no: number) {
          this.no = no;
        }
      
        getNo() {
          return this.no;
        }
      }

       

      🔗  클래스 속성

       

      아래 코드를 보면 name은 속성이며, draw()는 메서드를 가리킨다.

       

      class Shape {
          name: string;
       
          constructor(name: string) {
              this.name = name; // ok!
          }
          
          // 존재하지 않는 멤버의 접근하려고 시도하면 타입 오류
          this.nonName = name; //Error
       
          draw(x: number, y: number) {
              console.log("Draw " + this.name + " at " + x + "," + y);
          }
      }

       

      TS에서는 클래스의 속성을 읽거나 쓰려면 클래스에 명시적으로 선언

      클래스 속성 이름 뒤에 선택적으로 타입 에너테이션이 붙는다.

       

       

       

      🔗  함수 속성

       

      JS에서의 클래스 안에 함수 선언1

       

      // 멤버 이름 뒤에 괄호를 붙이는 메서드 접근 방식
      class WithMethod{
      	myMethod(){}
      }
      
      new WithMethod().myMethod === new WithMethod().myMethod;// true

       

      JS에서의 클래스 안에 함수 선언2

       

      // 값이 함수인 속성을 선언하는 방식
      class WithPtoperty{
      	myProperty : () => {}
      }
      
      new WithMethod().myProperty === new WithMethod().myProperty; // false

       

      함수 속성은 클래스 멤버로 할당된 값 👉🏼👉🏼 그 값은 함수

       

      (input : boolean) => string 인 속성을 갖고 있어 number속성은 바로 에러를 알려준다.

       

       

       

      🔗  초기화 검사

       

      타입스크립트는 엄격한 컴파일러 설정이 활성화되어 있는 상태

      undefined 타입으로 선언된 각 속성이 생성자에서 할당되었는지 확인

      초기화 검사는 클래스 속성에 값을 할당하지 않는 실수를 예방할 수 있어 유용하다.

       

      class WithValue{
          immediate = 0; // ok
          later : number; // ok(construtor에서 할당)
          mayBeUndefined : number | undefined; // Ok(undefined가 되는 것이 허용됨)
          unused : number; // Error
      
          constructor(){
              this.later = 1;
          }
      }

       

       

      🔗  선택적 속성

       

      클래스는 설정된 인터페이스에 정의된 속성 또는 메서드를 반드시 사용하지 않고, 필요에 따라 선택적으로 사용하고 싶을 수도 있다.

      이 경우 옵션(Optional) 속성 설정을 통해 사용자가 선택적으로 사용하게 설정

       

       

      더보기

      속성 이름 뒤에 ?를 붙이면 옵션 속성

       

      interface에서 선택적 속성을 이용해서 선언 후 클래스를 선언 해 상속시키는 예제

       

      // 공식사이트 예제
      interface ButtonInterface {
        // 속성 이름 뒤에 ? 기호가 붙으면 옵션 속성이 됩니다.
        onInit?():void;
        onClick():void;
      }
      
      class ButtonComponent implements ButtonInterface {
      
        // onInit 메서드가 설정되지 않아도 오류를 발생하지 않습니다.
        onClick() { console.log('버튼 클릭') }
      
      }

       

       

      🔗  읽기 전용 속성(readonly)

       

      말 그대로 읽기 전용을 나타내며 사용할 경우 값 변경 불가

       

      class Site {
      // readonly 사용
        readonly no: number;
        url: string;
      
        constructor(no: number, url: string) {
          this.no = no;
          this.url = url;
        }
      }
      
      const Webisfree = new Site(1, 'webisfree.com');
      
      Webisfree.no = 2;
      // 에러 발생. Readonly이므로 값 변경이 불가함

       

       

      🔗  타입으로서의 클래스

       

       

       

      타입 시스템은 클래스 자체와 타입 에너테이션에서 사용할 수 있는 타입을 모두 생성하는 부분이 특징이다.

      타입 에너테이션을 통해 할당할 수 있는 값만을 타입 스크립트에서 알려준다.

      타입스크립트는 클래스의 동일한 멤버를 모두 포함하는 객체 타입 클래스만 할당 가능하다

       

      class Teacher {
          sayHello(){
              console.log("Hello");
              }
      }
      
      let teacher : Teacher;
      teacher = new Teacher(); //ok
      teacher = "Wahoo!"; 
      // error string 형식은 할당할 수 없습니다.

       

       

       

      🔗 클래스와 인터페이스

       

      🙋🏻‍♂️ 인터페이스란? 클래스나 객체에서 사용할 프로퍼티와 메소드를 클래스 외부에 따로 분리하여 선언할 수 있는 방법

       

      타입스크립트는 클래스 이름 뒤에 implements를 사용하여 클래스나 객체에 사용

      아까 선택적 속성의 예제와 같이 볼 수 있다.

       

       

      // 공식사이트 예제
      interface ButtonInterface {
        // 속성 이름 뒤에 ? 기호가 붙으면 옵션 속성이 됩니다.
        onInit?():void;
        onClick():void;
      }
      
      class ButtonComponent implements ButtonInterface {
      
        // onInit 메서드가 설정되지 않아도 오류를 발생하지 않습니다.
        onClick() { console.log('버튼 클릭') }
      
      }
      
      class ButtonComponent implements ButtonInterface {
      
      	// 아무 메서드도 정의 되어 있지 않다면 에러 발생
        }

       

       

      interface는 사용할 프로퍼티와 타입을 분리하여 사용할 수 있는 방법입니다. 이처럼 interface를 사용할 경우 동일한 데이터를 여러 번 사용할 때 반복해서 프로터티나 타입 등을 선언하지 않아도 된다는 장점이 있다.

       

       

      // 인터페이스 만들기
      interface ISite {
        no: number;
      }
      
      // 객체에 인터페이스 사용하기
      const mySite: ISite = {
        no: 1
      };
      
      // 함수에 인터페이스 사용하기
      const getSiteNo = (site: ISite) => {
        return site.no;
      };

       

       

      타입 에너테이션을 제공하지 않으면 any로 간주

      다중 인터페이스로도 구현 가능하다(개수 제한 없이 인터페이스 사용 가능)

       

      class Site implements ISite, IFavorite {
      }

       

       

      🔗 클래스 확장

      클래스는 확장이 가능

      확장하는 개념에서 타입스크립트는 타입 검사를 추가한다.

       

       

      풀스택, 백엔드, 프론트엔드 개념으로 알아보기

       

      export class FrontEnd {
          public frontEndSkills = ["html", "css", "js"]
      public react = () => {
              console.log('I write code with React')
          }
      }
      // FrontEnd.ts
      
      // 확장해주면 FrontEnd.ts의 멤버 변수와 메소드에 접근 가능
      export class FullStack extends FrontEnd{
          public name: string
          public age: number
      constructor(name: string, age: number) {
              super()
              this.name = name
              this.age = age
          }
      }
      // FullStack.ts

       

      🤷🏻 백엔드를 추가하고 싶다면?

       

      export interface BackEndType {
          backendSkills: Array<string>
          django: () => void
      }
      export class BackEnd {
          public backendSkills = ["database", "aws", "restapi"]
      public django() {
              console.log('I build things with django')
          }
      }
      // BackEnd.ts
      
      export class FullStack extends FrontEnd, BackEnd{ // Error
          public name: string
          public age: number
      constructor(name: string, age: number) {
              super()
              this.name = name
              this.age = age
          }
      }
      //Error FullStack.ts

       

      mixin 함수를 추가

      프론트엔드클래스를 상속받은 풀스택 클래스 베이스 클래스로 만들어 백엔드 클래스와 확장해주면 된다.

       

       

      const FullStackExtension = <T extends Constructor>(baseClass: T) => {
          return class FrontEnd extends baseClass {
              public frontEndSkills = ["html", "css", "js"] as const
      public react = () => {
                  console.log('I write code with React')
              }
          }
      }
      // FullStack.ts
      
      
      export class FullStack extends FullStackExtension(BackEnd) {
          public name: string
          public age: number
      constructor(name: string, age: number) {
              super()
              this.name = name
              this.age = age
          }
      }
      // FullStack.ts

       

       

      🔗 재정의된 생성자, 메서드, 속성

       

      생성자

       

      JS에서 상속받은 하위 클래스에서는 자체 생성자가 없고 기본 클래스의 생성자를 사용

      super라는 키워드를 통해 생성자를 호출한다.

      TS에서는 기본클래스의 생성자를 호출 할 때 올바른 매게변수를 사용했는지 확인

      예를 들어, class B,C가 A에 상속받는 때 이때 C에서 super라는 키워드 없이 생성자를 생성하면 오류

      타입 검사기에서 super() 호풀 전에 A에 있는 메서드의 타입을 참조하기 때문이다.

       

       

      메서드

       

      하위 클래스의 메서드가 기본 클래스의 메서드에 할당될 수 있는 한 하위 클래스는 기본 클래스와 동일한

      이름으로 새 메서드를 다시 선언할 수 있다.

      기본 클래스의 모든 메서드 👉🏼👉🏼 하위 클래스에서 사용 가능 새 메서드 타입도 기본 메서드 대신 사용할 수 있어야 한다! 

       

      속성

       

      하위 클래스는 새 타입을 기본 클래스의 타입에 할당할 수 있는 한 동일한 이름으로 기본 클래스의 속성을 명시적으로 다시 선언

      재정의된 메서드와 마찬가지로 하위 클래스는 기본 클래스의 구조적으로 일치해야 한다.

      예를 들어, 기본 클래스의 grade가 number | undefined라면 하위 클래스 또한 number타입으로 선언해야 한다.

       

       

       

      🔗 추상 클래스

       

      추상 클래스를 정의할 때는 class 앞에 abstract라고 표기

      때로는 일부 메서드의 구현을 선언하지 않고, 대신 하위 클래스가 해당 메서드를 제공할 것을 예상하고

      기본 클래스를 만드는 방법이 유용할 수 있다.

       

      // 추상 클래스
      abstract class Project {
      
        public project_name:string|null = null;
        private budget:number = 2000000000; // 예산
      
        // 추상 메서드 정의
        public abstract changeProjectName(name:string): void;
      
        // 실제 메서드 정의
        public calcBudget(): number {
          return this.budget * 2;
        }
      
      }
      
      // [오류]
      // [ts] 추상 클래스의 인스턴스를 만들 수 없습니다.
      // constructor Project(): Project
      let new_project = new Project();

       

       

       

      🔗 멤버 접근성

       

      접근 제한자 public, private, protected를 지원

      #을 추가해 private 클래스 멤버임을 나타낸다.

       

      접근 범위 public protected private
      클래스 내부 O O O
      자식 클래스 내부 O O X
      클래스 인스턴스 O X X

       

       

      class Animal {
        constructor(public name: string, protected age: number, private breed: string) {
          this.name = name;
          this.age = age;
          this.breed = breed;
        }
      
        protected talk() {
          console.log(`this animal's name is ${this.name}`);
        }
      }
      
      const animal = new Animal("Ruby", 2, 'tlrhfmwkqmwhd');
      
      // error : 'talk' 속성은 보호된 속성이며 'Animal' 클래스 및 해당 하위 클래스 내에서만 액세스할 수 있습니다.
      animal.talk();
      
      class Dog extends Animal{
        constructor(name: string, age: number, breed: string) {
          super(name, age, breed);
      
          this.talk();
          console.log(this.age);
          
          // error : 'breed' 속성은 private이며 'Animal' 클래스 내에서만 액세스할 수 있습니다.
          console.log(this.breed);
        }
      }
      
      
      // this.talk(): this animal's name is Ruby
      // this.age: 5
      const dog = new Dog("Ruby", 5, 'tlrhfmwkqmwhd');

       

      🔗 정적 필드 제한자

       

      static 키워드를 사용해 인스턴스를 생성할 필요 없이, 클래스 자체에서 멤버를 선언 

      readonly의 접근성 키워드를 함께 사용할 수 있도록 지원

       

       

      class Mathmatics {
      
        // 스태틱 속성
        static PI:number = Math.PI;
      
        // 스태틱 메서드
        // circumference = 둘레(원주)
        static calcCircumference(radius:number) :number {
          return this.PI * radius * 2;
        }
      
        static calcCircleWidth(radius:number): number {
          return this.PI * Math.pow(radius, 2);
        }
      
      }
      
      // radius = 반지름
      let radius = 4;
      
      console.log('PI(원주율) = ', Mathmatics.PI);
      console.log(`반지름이 ${radius}인 원의 넓이: πr² = `, Mathmatics.calcCircleWidth(radius));
      console.log(`반지름이 ${radius}인 원의 둘레: 2πr = `, Mathmatics.calcCircumference(radius));

       

      반응형

      'codeStates front-end > Typescript' 카테고리의 다른 글

      [TS] 제네릭  (0) 2023.03.23
      [TS] 타입 제한자  (0) 2023.03.21
      [TS] 인터페이스  (0) 2023.03.12
      [TS] 배열과 튜플  (0) 2023.03.12
      [TS] 함수  (0) 2023.03.12

      댓글

    Designed by Tistory.