[KDT]FCFE - 6주2일 2. TypeScript (classes, generic)

Keunyeong Lee·2021년 12월 28일
0
post-thumbnail

Classes

constructor(구조) & initialize(초기화)

class Person {
  name: string; //  할당되지 않아 초기화 오류 발생.
  age!: number; //  할당되지 않아 초기화 오류가 있더라도 다른 곳에서 할당하기 때문에 넘어간다는 표시.
}
  • strict 모드에서는 프로퍼티를 선언하는 곳 또는 생성자에서 값을 할당해야 한다.

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

  • 생성자에는 async 를 설정할 수 없다.

  • tsconfig.json 에 strict 옵션을 끄면 초기화 오류가 표시되지 않는다.

  • 초기화 오류를 표시해주지 않아서 그냥 넘어간다면 초기화 되어있지 않아 undefined 이므로 오류가 발생한다.

class Person {
  name: string; 
  age!: number;

  constructor(name: string){
    this.name = name;
  }
}
  • 객체의 기본 상태를 설정해주는 생성자 메서드 constuctor()

  • constructor를 활용하여 설정해주면 초기화 오류가 발생하지 않는다.

  • constructor에는 비동기적인 처리를 위해 async 를 붙일 수 없다.

  • class 안에 메서드에 async 를 붙여 비동기 처리를 하도록 한다.

Access Modifiers(접근 제어자)

  • Javascript 에서는 Access Modifiers 를 제공하지 않는다.
    ( 암묵적으로 _ 를 활용하여 외부에서 사용하지 않겠다는 컨벤션만 존재한다.)

  • 접근 제어자에는 public, private, protected 가 있다.

  • TypeScript는 기본적으로 모두 외부에서 접근이 가능하다.(public)

  • TypeScript class 내부 모든 곳에 접근 제어자 설정 가능.

  • 접근 제어자 private 는 외부에서 호출할 수 없도록 한다.

class Person {
  private name: string; 
  public age!: number;

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

initialization in constructor parameters

  • 코드량이 줄어든다.

  • public을 붙여주면 this.name = name; 으로 다시 할당문을 적어줄 필요없이 name 인자가 name 에 할당된다.

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

const p1: Person = new Person("Mark", 39);
console.log(p1); // { name:"Mark", age:39 };
  • private는 접근이 내부에서만 가능하다.
class Person {
  public constructor(public name: string, public age: number){}
}

const p1: Person = new Person("Mark", 39);
console.log(p1.name); // "Mark"

Getters & Setters

class Person {
  public constructor(private _name: string){}
  
  // 출력(내용을 가져간다.)
  get name(){
  	return this._name + "lee";
  }
  
  // 입력(내부에 접근하여 내용 변경)
  set name(n: string){
  	this._name=n;
  }
}
  • private를 해놓으면 내부에 함수인 get 과 set을 통해서만 접근할 수있다.

readonly properties

class Person {
  public readonly name: string = "Mark";
  private readonly country: string = "Korea";
  
  public constructor(private _name: string){}
  
  hello(){
    ~~this.country ="China";~~ // Error! readonly는 다른곳에 바꿀수 없다.
  }
}

Index Signatures in class

  • property name(index) 이 동적일 때 사용한다.
class Students {
  [index: string]: string; 
  // property 이름이 string이고 property 값도 string 이다.
}
class Students {
  [index: string]: "male" | "female"; 
  // property 이름이 string이고 property 값이 "male" 이거나 "female" 이다.
}

Static Properties & Methods

  • object 를 생성하지 않고 class 로 바로 사용하기

  • 데이터가 공유된다.

class Person {
  private static CITY = "Seoul";
  public static hello() {
    console.log("안녕하세요", Person.CITY);
  }
}

Person.hello(); // 안녕하세요Seoul

Singletons

  • static의 활용.

  • singleton petern ( 단일 객체 패턴 )

class ClassName {
  private static instance: ClassName | null = null;
  public static getInstance(): ClassName {
    // ClassName 으로부터 만든 object 가 있으면 그걸 리턴
    // 없으면, 만들어서 리턴
    if ( ClassName.instance === null ) {
      ClassNmae.instance = new ClassName();
    }
    
    return ClassName.instance;
  }
  
  private constructor() {}
}

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

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

Inheritance(상속)

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, this._age);
  }
}

const p = new Parent('Mark', 30);

class Child extends Parent {
  public gender = "male";

  constructor(age: number){
    //super 이용해 먼저 부모의 프로퍼티를 받아와 줘야 오류가 없다.
    super("Mark Jr",age); 
    
    this.printName();
  }
}

const c = Child(1);

c.print();

Abstract Classes ( 추상 클래스 )

abstract class AbstractPerson {
  protected _name: string = "Mark";
  
  //구현하지 않은 빈 메소드를 만든다.
  abstract setName(name: string):void;
}

// implement inherited
class Person extends AbstractPerson {
  setName(name:string): void {
  	this._name = name;
  }
}

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

Generics

function helloGeneric<T>(message: T): T {
  return message;
}

Generics, Any 와 다른점

  • any는 아무거나로 이후 생길 오류에 취약하다.

  • any로 계속 전달된다.

  • generic은 추론되어 올바르게 사용된다.

function helloGeneric<T>(message: T): T {
  return message;
}

helloGeneric("Mark").length; // "Mark" type (string type 하위)
helloGeneric(39); // 39 type (number type 하위)
helloGeneric(true); // true type

Generics Basic

// 여러개 generic 설정
function helloGeneric<T, U>(message: T, comment: U): T {
  return message;
}

// 지정해주기
helloGeneric<string, number>("Mark", 39); // string type, number type
// 안넣으면 추론.
helloGeneric(39, 29); // 39 type, 29 type

Generics Array & Tuple

function helloGeneric<T>(message: T[]): T {
  return message[0];
}

helloGeneric(["hello","world"]); // string type
helloGeneric(["hello",5]); // string | number union type

function helloTuple<T,K>(message: [T,K]): T {
  return message[0];
}

helloTuple(["hello","world"]); // hello type, world type
helloTuple(["hello",5]); // hello type, 5 type

Generics Function

type HelloFunctionGeneric1 = <T>(message: T)=>T;

const helloFunction1: HelloFunctionGeneric1 = <T>(message: T): T =>{
  return message;
};

interface HelloFunctionGeneric2 {
  <T>(message: T):T;
}

const helloFunction2: HelloFunctionGeneric2 = <T>(message: T): T =>{
  return message;
};

Generics Class

class Person<T,K> {
  private _name: T;
  private _age: K;
  constructor(name: T, age: K){
    this._name = name;
    this._age = age;
  }
}

new Person("Mark", 29);
new Person<string, number>("Mark", 29);

Generics with extends

  • generic 도 상속으로 사용할 수 있다.

  • generic 에 직접 상속.

class PersonExtends<T extends string | number> {
  private _name: T;
  
  constructor(name: T){
    this._name = name;
  }
}

type 최소한의 범위로 설정하는것이 오류를 막는다.

keyof & type lookup system

const person: IPerson = {
  name: "Mark",
  age: 39,
};

function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
profile
🏃🏽 동적인 개발자

0개의 댓글