[엘리스] 5주차-3 복습 정리

Hyejis·2023년 1월 30일
0

엘리스

목록 보기
8/11

Interface와 Generic

1. Interface

1) Interface

변수, 함수, 클래스에 타입 체크를 위해 사용됨
직접 인스턴스를 생성할 수 없으며 모든 메소드가 추상 메소드지만 abstract는 사용할 수 없다.
타입의 이름을 짓고 코드 안의 계약을 정의한다.

function hi(obj: {name: string}){
  console.log(obj.name);
}
let person = {name: "bibi"};
hi(person);
interface Itype{
  name: string
}
function hi(obj:Itype){
  console.log(obj.name);
}
let person = {name: "bibi"};
hi(person);

Interface를 추가해 함수 매개변수의 프로퍼티를 정의할 수 있다.

2) Properties

컴파일러는 필수 요소 프로퍼티의 유무와 프로퍼티 타입에 대해 검사한다.

  • ?(Optional Properties)
    프로퍼티 선언 시 이름 끝에 ?를 붙여서 표시
    인터페이스에 속하지 않는 프로퍼티의 사용을 방지
    객체 안의 몇 개의 프로퍼티만 채워 함수에 전갈하는 option bags 패턴에 유용
interface IType{
  color?: string
  width?: number
}
  • readonly(Readonly Properties)
    객체가 처음 생성될 때만 값 설정 가능, 이후 수정 불가
    프로퍼티 이름 앞에 readonly를 붙여 사용
interface IType{
  readonly x: number
  readonly y: number
}
let point: Point = {x: 10, y: 20};
point.x = 5; // error

=> const와 공통점: 생성 후 배열을 변경하지 않음을 보장
=> const와 차이점: 변수는 const, 프로퍼티는 readonly

let arr: number[] = [1, 2, 3, 4];
let readonly_arr: ReadonlyArray<number> = arr;
readonly_arr.push(5) // error

3) Interface Type

인터페이스는 함수, 클래스에서 사용가능

  • Function Type: JS객체가 가질 수 있는 넓은 범위의 형태를 기술
    함수 인자의 타입과 반환 값의 타입 정의
interface IType{
  (name: string, num: number):boolean
}
let hiName: IType
hiName = function(na, nu){
  if(na.string === nu) retrun true
  else return false
}
  • Class Tpye: 클래스가 특정 통신 프로토콜을 충족하도록 명시적으로 강제
interface Itype {
  name(): void
}
class person implements Itype {
  name(): void{
    console.log("bibi");
  }
}
  • Interface Extends: 인터페이스 간의 확장 가능
interface Itype {
  name(): void
}
interface baby extends Itype {
  speed: number
}
class person implements Itype {
  name(): void{
    console.log("bibi");
  }
}
  • Hybrid Type: 여러 가지 타입 조합 가능(함수 타입이면서 객체 타입을 정의할 수 있는 인터페이스 구현 가능)
interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}
function getCounter(): Counter {
    let counter = function (start: number) {} as Counter;
    counter.interval = 123;
    counter.reset = function () {};
    return counter;
}

4) 디자인 패턴(Strategy Pattern)

객체가 할 수 있는 행위들을 전략으로 만들어두고 동적으로 행위의 수정이 필요한 경우 전략을 바꾸는 것만으로 수정이 가능하도록 만든 패턴

  • 메소드 수정 방식의 경우 시스템이 커져서 확장되면 연동되는 시스템에도 영향을 줄 수 있는 문제가 있는데, 이는 디자인 패턴으로 해결할 수 있다.

2. Generic

1) Generic

코드가 수행될 때 타입을 명시하며, 작성 시에는 식별자를 써서 아직 정해지지 않은 타입을 표시
일반적으로 식별자는 T, U, V를 사용하거나 필드 이름의 첫 글자를 사용

  • 재사용성이 높은 함수와 클래스 생성 가능
    여러 타입에서 동작 가능 및 코드의 가독성 향상

  • 오류를 쉽게 포착 가능
    any처럼 미리 타입을 지정하지는 않지만 타입을 체크해 컴파일러가 오류를 찾을 수 있다.

2) Generic을 이용해 function, class 만들기

Function

function person<T>(items: T[]): T[]{
  return items.person();
}
const year: number[] = [12, 20, 33, 45];
const names: string[] = ["aie", "bibi", "chin", "dony"];
person<number>(year);
person<string>(names);

Class

class Queue<T>{
  protected data: Array<T>=[];
  push(item: T){
    this.data.push(item);
  }
  pop(): T|undefined{
    return this.data.shift();
  }
}
const numQueue = new Queue<number>();
numQueue.push(0);
numQueue.push("1");	// 의도하지 않은 실수 사전 검출 가능
numQueue.push(+"1");	// 실수 사전 인지 및 수정 가능

3) Union type

"|"를 사용해 두 개 이상의 타입을 선언
Generic 또한 여러 타입을 다룰 수 있으나 Union은 선언한 공통된 메소드만 사용 가능하며 리턴 값이 선언된 Union 타입으로 지정된다는 점에서 다르다.

// union
const hi = (person: string | number) => {
  return person;
}
const person1 = hi("bibi");
const person2 = hi(20);
person1.length; // error
// generic
const hi = <T>(person: T) => {
  return person;
}
const person1 = hi<String>("bibi");
person1.length; // no error

4) 제약조건(Constraints / keyof)

원하지 않는 속성에 접근하는 것을 막기 위해 Generic에 제약조건을 사용

Constrains

특정 타입들로만 동작하는 Generic 함수를 만들 때 Generic T에 제약 조건 설정

const hi = <T extends string | number>(person: T):T => {
  return person;
}
hi<String>("bibi");
hi<Number>(20);
// 다른 타입은 에러 발생

Keyof

두 객체를 비교

const hi = <T extends object, U extends keyof T>(obj: T, key: U) => {
  return obj[key]
}
hi({aie: 10, bibi: 20, ceci: 30}, "bibi");

U의 값인 "bibi"가 Generic T의 값 중 존재하므로 오류가 발생하지 않는다.
Generic T는 키 값이 aie, bibi, ceci만 존재하는 object이다.

5) Design pattern(Factory Pattern with Generics)

객체를 생성하는 인투페이스만 미이 정의하고 인스턴스를 만들 클래스의 결정은 서브 클래스가 내리는 패턴
슈퍼 클래스가 있을 때 입력에 따라 하나의 서브클래스 인스턴스를 반환
슈퍼 클래스: 여러 개의 서브 클래스를 가진 클래스

Factory Pattern

interface Animals {
  bark(): void
  walk(): void
}
class Dog implements Animals {
  bark(): void {}
  walk(): void {}
}
class Cat implements Animals {
  bark(): void {}
  walk(): void {}
}
class Home {
  static getInstance(type: String): Animals {
    // Animals의 type이 추가될 때마다 case문도 추가해야함 
    switch (type) {
      case "dog":
        return new Dog();
      default:
        return new Cat();
    }
  }
}
const dog = Home.getInstance("dog");
const cat = Home.getInstance("cat");

Factory Pattern with Generics

interface Animals {
  bark(): void
  walk(): void
}
class Dog implements Animals {
  bark(): void {}
  walk(): void {}
}
class Cat implements Animals {
  bark(): void {}
  walk(): void {}
}
class Hamster implements Animals {
  bark(): void {}
  walk(): void {}
}
export class Home {
  static getInstance<T extends Animals>(type: {new (): T}}: T {
    return new type();
  }
}
const dog = Home.getInstance("dog");
const cat = Home.getInstance("cat");
profile
프론트를 시작으로 풀스택을 걸쳐 모든 분야를 아우르고 싶은 야망이 살짝 있는 아기 개발자입니다.

0개의 댓글