Overload

동일한 매개변수이지만 갯수나 타입에 따라 다른 타입의 return 값이 반환될 때 overload 처리한다.

interface User {
  name: string;
  age: number;
}

function memberDB(name: string, age: number | string): User | string  {
  if (typeof age === 'number') return {name, age};
  else return 'age 는 숫자 형식이야 합니다.'
}

const David: User = memberDB('David', 20);
const Emily: string = memberDB('Emily', '30');

위의 코드 작성 시 함수를 호출하는 변수에 타입을 지정하면 함수에서 출력되는 타입과 다를 수도 있기 때문에 에러가 표시된다.

아래와 같이 함수 선언 전에 인자값과 출력값에 따른 타입을 별도로 지정해주면 에러를 표시하지 않는다.

interface User {
  name: string;
  age: number;
}

function memberDB(name: string, age: number): User;
function memberDB(name: string, age: string): string;
function memberDB(name: string, age: number | string): User | string {
  if (typeof age === 'number') return {name, age};
  else return 'age 는 숫자 형식이야 합니다.'
}

const David: User = memberDB('David', 20);
const Emily: string = memberDB('Emily', '30');


this

this 를 파라미터같이 작성하고 타입을 할당하면 this 값이 바인딩 될 때의 타입을 지정할 수 있다.

interface User {
  name: string;
}

const member = { name: 'Yujoo'};

function test(this: User) { // this 의 타입 지정
  console.log(`I am ${this.name}!`);
}

test.bind(member)();


Union Type

파라미터로 전달받는 값의 타입이 여러 종류라면 | 연산자로 복수개의 타입이 오도록 지정한다.

interface iphone {
  name: 'iphone';
  color: string;
  apple(): void;
}

interface galaxy {
  name: 'galaxy';
  color: string;
  samsung(): void;
}

function buyCellphone(product: iphone | galaxy) {
  console.log(product.color);
  product.name === 'iphone' && product.apple();
  product.name === 'galaxy' && product.samsung();
}


Intersection Type

여러 타입을 모두 만족하는 타입을 지정하고 싶으면 & 연산자로 복수개의 타입이 오도록 지정한다.

interface Action {
  name: string;
  play(): void;
}

interface Rpg {
  name: string;
  price: number;
}

const actionRpg: Action & Rpg = {
  name: 'Diablo',
  play() {
    console.log('Play');
  }
}

위 코드의 객체는 지정한 두개의 타입을 모두 만족해야 하는데 price 값이 없으므로 에러를 반환한다.


class 접근 제한자

접근 제한자로 class 에서 만든 프로퍼티나 메서드의 접근 범위를 지정할 수 있다.


public

public 은 해당 프로퍼티 또는 메서드를 모든 범위에서 호출할 수 있도록 지정한다.

class Phone {
  name: string = 'phone';
  color: string;

  constructor(color: string) {
    this.color: color;
  }

  info() {
    console.log('phone');
  }
}

위와 같은 상위 class 가 있을 때, 아래와 같이 하위 class 에서 상속받는다.

이때 접근 제한자를 지정하지 않으면 기본값은 public 으로 모든 범위에서 호출할 수 있게 된다.

class Iphone extends Phone {
  constructor(color: string) {
    super(color); // 상위 class의 color 값 상속
  }
  showInfo() {
    console.log(super.name);
  }
}

따라서 위의 코드는 에러를 반환하지 않는다.


private

하지만 아래와 같이 private 로 접근을 제한하면 선언된 class 가 아닌 외부 class 에서 호출했을 때 에러를 표시한다.

class Phone {
  private name: string = 'phone';
  color: string;

  constructor(color: string) {
    this.color: color;
  }

  info() {
    console.log('phone');
  }
}

class Iphone extends Phone {
  constructor(color: string) {
    super(color);
  }
  showInfo() {
    console.log(super.name);  // Error
  }
}

private# 으로도 대체 가능하다.

class Phone {
  #name: string = 'phone';  // private 와 동일
  ...
}


protected

선언된 class 와 상속받는 하위 class 에서는 호출할 수 있지만, 외부에서는 호출할 수 없다.

class Phone {
  protected name: string = 'phone';  // private 와 동일
  ...
}

class Iphone extends Phone {
  ...
  showInfo() {
    console.log(super.name);  // 호출 가능
  }
}

const a = new Iphone('blue');
console.log(a.name);  // Error


readonly

값을 읽을 수는 있지만 변경은 불가하도록 지정한다.

class Phone {
  readonly name: string = 'phone';
  ...
}

class Iphone extends Phone {
  ...
  showInfo() {
    console.log(super.name);
  }
}

const a = new Iphone('blue');
console.log(a.name);  // 호출 가능
a.name = 'TV';  // Error


static

static 으로 지정하면 생성한 모든 인스턴스에 공통으로 값이 유지된다.

static 으로 지정한 변수는 클래스가 메모리에 올라갈 때 자동으로 생성되므로 인스턴스 생성없이 호출할 수 있다.

또한 인스턴트에 생성된 것이 아닌 class 자체에 생성되었으므로 this 로 호출할 수 없다.

static 과 public / protected / private 은 함께 지정할 수 있다.

class Phone {
  readonly name: string = 'phone';
  static cameraNum = 2;
  ...
}

class Iphone extends Phone {
  ...
  showInfo() {
    console.log(super.name);
    console.log(Phone.cameraNum); // this.cameraNum 은 error
  }
}


Generic

파라미터로 전달되는 타입의 경우의 수가 많아지면 Generic 으로 지정할 수 있다.

함수 선언 시 <> 으로 전달받아 적용할 타입을 변수로 지정하고 호출 시 상황에 맞게 타입을 적용시킨다.

function func(arr: number[] | string[] | boolean[]): number {
  return arr.length;
}

test([1, 2, 3]);
test(['a', 'b', 'c']);
test([true, false]);

위의 코드는 아래와 같이 수정할 수 있다.

function func<custom>(arr: custom[]): number {
  return arr.length;
}

test<number>([1, 2, 3]);
test<string>(['a', 'b', 'c']);
test<string | number | boolean>(['a', 2, true]);

Generic 은 배열 보다는 객체값을 전달할 때 유용하게 쓰인다.

interface Vehicle<t> {
  name: string;
  price: number;
  option: t;
}

const sonata: Vehicle<string> = {
  name: 'sonata',
  price: 4000,
  option: 'good',
}

const genesis: Vehicle<{hud: boolean, cameraNum: number}> = {
  name: 'genesis',
  price: 9000,
  option: {
    hud: true,
    cameraNum: 5,
  },
}