Elice SW engineer - TIL day 25

Circlewee·2022년 5월 6일
0

Elice SW 2 TIL

목록 보기
23/31

1. Interface

1.1 What is intrface?

  • 변수와 함수, 클래스에 타입 체크를 위해 사용.
  • 직접 인스턴스를 생성할 수 없으며 모든 메소드가 추상 메소드이다. => 모두 구현해야한다.(다만 abstract 키워드는 사용할 수 없음)
  • ES6에 존재하지 않는 문법

1.2 Properties

  • 컴파일러는 필수요소 프로퍼티의 유무, 프로퍼티 타입을 검사한다.

  • ?, readonly예약어로 프로퍼티를 컨트롤할 수 있다.
    1. ?: 반드시 속하는 프로퍼티가 아니면서 사용 가능함을 알려주기 위해 사용d

    interface Circle {
      radius: number;
      color?: string;
    }
    
    const circle: Circle = { radius: 10 } // not error

    2.Readonly: 객체가 처음 생성될 때만 값 설정이 가능하고, 이후 수정이 불가능함

    interface Point {
      readonly x: number;
      readonly y: number;
    }
    
    const point: Point = { x: 10, y: 10 }
    point.x = 20; // error
    1. readonly vs const: 생성 후 변경하지 않음을 보장. 변수에 const, 프로퍼티에 readonly를 사용한다.
    let arr: Array<number> = [1, 2, 3, 4];
    let readonly_arr: ReadonlyArray<number> = arr;
    
    readonly_arr[0] = 12; // error
    readonly_arr.push(5); // error

1.3 Interface types

  1. 함수
    • JS객체가 가질 수 있는 넓은 범위의 형태를 기술한다.
    • 프로퍼티로 객체를 기술하는 것 외에도, 인터페이스는 함수 타입을 설명한다.
    • 함수의 타입추론으로 이어짐
interface IArea {
  (width: number, height: number): number;
}

// 아래 함수에서 w: number, h: number이다.
function calArea: IArea = (w, h) => {
  return w * h;
  // return 'hello' => error
}
  1. 클래스
    • 클래스가 특정 통신 프로토콜(contract)을 충족하도록 명시적으로 강제한다.
    • C#과 Java와 같은 언어에서 인터페이스를 사용하는 방법과 동일하다.
  • 인터페이스간 확장이 가능(extends 사용)

1.4 정리

  • 제일 유명한 설명인 붕어빵 틀
  • type과의 차이점은 확장이 가능하다는 것이다. (아래 예제의 interface extends)
// 배열의 경우 아래처럼 이용할 수 있다.
interface Person {
    [index: number]: string;
}
let people: Person = ["rabbit", "cheshire", "queen"];
interface shapeInterface {
    getArea(): number;
}

interface triangleInterface extends shapeInterface {
    width: number;
    height: number;
}

interface circleInterface extends shapeInterface {
    radius: number;
}

// this를 사용하기 위해선 내부에 width와 height를 명시해줘야 하지만 public으로 인자를 받으면 생략할 수 있다.
class triangle implements triangleInterface {
    constructor(public width: number, public height: number) {
        this.width = width;
        this.height = height;
    }

    getArea() {
        return (this.width * this.height) / 2;
    }
}

// parameter를 public으로 선언하면 this를 이용한 값 초기화를 생략할 수 있다.
class circle implements circleInterface {
    constructor(public radius: number) {}

    getArea() {
        return Math.PI * Math.pow(this.radius, 2);
    }
}

2. Generic

  • 정적 type언어에서 코드가 수행될 때 타입을 명시하는 방법
  • 식별자를 써서 정해지지 않은 타입을 표시하고 T, U, V...를 많이 사용한다.
  • 사용하는 이유
    1. 재사용성이 높은 함수와 클래스를 생성할 수 있다.
    1. 오류를 쉽게 포착할 수 있다.(컴파일 시점에 버그를 찾을 수 있다.)
    2. 코드의 가독성이 향상된다.
class Queue<T> {
  protected data: Array<T> = [];
  
  push(item: T): void {
    this.data.push(item);
  }
  
  pop(): T | undefined {
    return this.data.shift();
  }
}

const numberQueue = new Queue<number>();
numberQueue.push(0);
numberQueue.push('1'); // error 사전 검출 가능
numberQueue.push(+'1'); // 위에서 인지한 error를 수정, 단항 더하기를 이용해 type을 변경하는 것이다.

2.1 Union type

  • |를 사용해 두 개 이상의 타입을 선언하는 방식
  • generic처럼 여러 타입을 다룰 수 있지만 Union 타입안에서 모든 것이 결정된다.
const printMessage = (message: string | number) => {
  return message;
}
const message1 = printMessage(1234);
const message2 = printMessage('hello world!');

// string과 number type의 공통된 메소드만 사용 가능하기 때문에 error출력 (string에 존재하여도)
console.log(message2.length);

2.2 제약조건(constraints, keyof)

  • Generic에서 원하지 않는 속성에 접근하는 것을 막기위해 사용하는 방법
  1. constraints: 특정 타입들로만 동작하는 Generic 함수를 만들 때 사용
function add<T extends string | number | boolean>(a: T, b: T) {
    if (typeof a === 'boolean') return a || b;
    return <any>a + <any>b;
}

console.log(add<number>(13, 15));
console.log(add<string>('hell', 'o'));
console.log(add<boolean>(false, true)); // error
  1. keyof: 두 객체를 비교할 때 사용
const getProperty = <T extends object, U extends T>(obj: T, key: U) => {
  return obj[key];
}

getProperty({a: 1, b: 2, c: 3}, "a"};
// error: Generic T는 키 값이 a, b, c만 존재하기 때문
getProperty({a: 1, b: 2, c: 3}, "z"};

2.3 Factory pattern

interface Car {
  drive(): void;
  park(): void;
}

class Bus implements Car {
  drive(): void {}
  park(): void {}
}

class Taxi implements Car {
  drive(): void {}
  park(): void {}
}
class CarFactory {
  static getInstance<T extends Car>(type: {new (/*no parameter*/): T}): T {
    return new type();
  }
}

const bus = CarFactory.getInstance(Bus);
const taxi = CarFactory.getInstance(Taxi);
  • 여기서 new (): T는 typescript의 constructor signature다.
    new()안에 인스턴스 생성시 필요한 argument가 있다면 parameter를 정의하면 된다.
    constructor의 shape를 서술하는 역할을 한다.
class Test {
    constructor(a: number){
       ...
    }
}
// would be {new(a: number): Test}

3. TSC의 작동 방식

  1. TS로 코드를 작성한다.
  2. 컴파일러가 코드를 AST(추상구문트리)라는 자료구조로 변환한다.
  3. 타입 검사기(Typechecker)가 AST의 코드의 타입 안정성을 검증한다.
  4. AST -> JS소스로 변환
    이 아래부터는 브라우저, Node js등이 수행한다.

  1. JS 소스 -> JS AST로 변환
  2. JS AST -> Bytecode로 변환
  3. JS 런타임이 Bytecode를 평가, 실행 결과를 보여준다.
profile
공부할 게 너무 많아요

0개의 댓글

관련 채용 정보