옹재
소소한 개발 블로그
옹재
전체 방문자
오늘
어제
  • 분류 전체보기 (66)
    • 개발 관련 서적 스터디 (6)
    • 프론트엔드 스터디 (36)
      • Javascript (16)
      • Typescript (13)
    • Vue 스터디 (22)
    • 개발 관련 스터디 (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 프론트엔드 스터디
  • 프레임워크 없는 프론트엔드 개발
  • scss
  • CSS
  • 개발서적 스터디

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
옹재
프론트엔드 스터디/Typescript

[TypeScript] 기초 - 제네릭(Generic)

프론트엔드 스터디/Typescript

[TypeScript] 기초 - 제네릭(Generic)

2021. 7. 21. 15:30
728x90
반응형

제네릭 (Generic)

제네릭은 C#, Java 등의 언어에서 재사용성이 높은 컴포넌트를 만들 때 자주 활용되는 특징입니다. 특히, 한가지 타입보다 여러 가지 타입에서 동작하는 컴포넌트를 생성하는데 사용됩니다.

타입스크립트는 정적 타입 언어이기 때문에 함수 또는 클래스를 정의하는 시점에 매개변수나 반환값의 타입을 선언하여야 합니다. 그런데 함수 또는 클래스를 정의하는 시점에 매개변수나 반환값의 타입을 선언하기 어려운 경우가 있습니다.

class Queue {
  protected data: any[] = [];

  push(item: any) {
    this.data.push(item);
  }

  pop() {
    return this.data.shift();
  }
}

const queue = new Queue();

queue.push(0);
queue.push('1'); // 의도하지 않은 실수!

console.log(queue.pop().toFixed()); // 0
console.log(queue.pop().toFixed()); // Runtime error

Queue 클래스의 data 프로퍼티는 any[] 타입입니다. any[]타입은 배열 요소의 타입이 모두 같지 않다는 문제가 있는데, 위 예제의 경우 number타입만을 포함하는 배열이라는 기대 하에 각 요소에 대해 Number.protoype.toFixed를 사용했습니다. 따라서 number 타입이 아닌 경우 런타임 에러가 발생합니다.

위와 같은 문제를 해결하기 위해 Queue 클래스를 상속하여 number 타입 전용 NumberQueue 클래스를 정의할 수 있습니다.

class Queue {
  protected data: any[] = [];

  push(item: any) {
    this.data.push(item);
  }

  pop() {
    return this.data.shift();
  }
}

// Queue 클래스를 상속하여 number 타입 전용 NumberQueue 클래스를 정의
class NumberQueue extends Queue {
  // number 타입의 요소만을 push한다.
  push(item: number) {
    super.push(item);
  }

  pop(): number {
    return super.pop();
  }
}

const queue = new NumberQueue();

queue.push(0);
// 의도하지 않은 실수를 사전 검출 가능
// error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
// queue.push('1');
queue.push(+'1'); // 실수를 사전 인지하고 수정할 수 있다

console.log(queue.pop().toFixed()); // 0
console.log(queue.pop().toFixed()); // 1

하지만 number 타입 이외의 요소가 추가되었을 때, 아래와 같이 런타임 이전에 에러를 감지할 수 있습니다.

vscode-code-validator

이러한 문제를 해결하기 위해 제네릭을 사용할 수 있습니다.

class Queue<T> {
  protected data: Array<T> = [];
  push(item: T) {
    this.data.push(item);
  }
  pop(): T | undefined {
    return this.data.shift();
  }
}

// number 전용 Queue
const numberQueue = new Queue<number>();

numberQueue.push(0);
// numberQueue.push('1'); // 의도하지 않은 실수를 사전 검출 가능
numberQueue.push(+'1');   // 실수를 사전 인지하고 수정할 수 있다

// ?. => optional chaining
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining
console.log(numberQueue.pop()?.toFixed()); // 0
console.log(numberQueue.pop()?.toFixed()); // 1
console.log(numberQueue.pop()?.toFixed()); // undefined

// string 전용 Queue
const stringQueue = new Queue<string>();

stringQueue.push('Hello');
stringQueue.push('World');

console.log(stringQueue.pop()?.toUpperCase()); // HELLO
console.log(stringQueue.pop()?.toUpperCase()); // WORLD
console.log(stringQueue.pop()?.toUpperCase()); // undefined

// 커스텀 객체 전용 Queue
const myQueue = new Queue<{name: string, age: number}>();
myQueue.push({name: 'Lee', age: 10});
myQueue.push({name: 'Kim', age: 20});

console.log(myQueue.pop()); // { name: 'Lee', age: 10 }
console.log(myQueue.pop()); // { name: 'Kim', age: 20 }
console.log(myQueue.pop()); // undefined

제네릭은 선언 시점이 아니라 생성 시점에 타입을 명시하여 하나의 타입만이 아닌 다양한 타입을 사용할 수 있도록 하는 기법입니다. T는 제네릭을 선언할 때 관용적으로 사용되는 식별자로 타입 파라미터라 합니다. T는 Type의 약자로 반드시 T를 사용하여야 하는 것은 아닙니다.

함수에도 제네릭을 사용할 수 있는데 제네릭을 사용하면 하나의 타입만이 아닌 다양한 타입의 매개변수와 리턴값을 사용할 수 있습니다.

function reverse<T>(items: T[]): T[] {
  return items.reverse();
}

const arg = [1, 2, 3, 4, 5];
// 인수에 의해 타입 매개변수가 결정된다.
const reversed = reverse(arg);
console.log(reversed); // [ 5, 4, 3, 2, 1 ]

const arg = [{ name: 'Lee' }, { name: 'Kim' }];
// 인수에 의해 타입 매개변수가 결정된다.
const reversed = reverse(arg);
console.log(reversed); // [ { name: 'Kim' }, { name: 'Lee' } ]
728x90
반응형

'프론트엔드 스터디 > Typescript' 카테고리의 다른 글

[TypeScript] 기초 - 타입 앨리어스(Type Alias)  (0) 2021.07.21
[TypeScript] 기초 - 타입 추론(Type Inference)  (0) 2021.07.21
[TypeScript] 기초 - 교차 타입(Intersection Type)  (0) 2021.07.21
[TypeScript] 기초 - 유니온 타입(Union Type)  (0) 2021.07.21
[TypeScript] 기초 - 리터럴 타입  (0) 2021.07.20
    '프론트엔드 스터디/Typescript' 카테고리의 다른 글
    • [TypeScript] 기초 - 타입 앨리어스(Type Alias)
    • [TypeScript] 기초 - 타입 추론(Type Inference)
    • [TypeScript] 기초 - 교차 타입(Intersection Type)
    • [TypeScript] 기초 - 유니온 타입(Union Type)
    옹재
    옹재

    티스토리툴바

    단축키

    내 블로그

    내 블로그 - 관리자 홈 전환
    Q
    Q
    새 글 쓰기
    W
    W

    블로그 게시글

    글 수정 (권한 있는 경우)
    E
    E
    댓글 영역으로 이동
    C
    C

    모든 영역

    이 페이지의 URL 복사
    S
    S
    맨 위로 이동
    T
    T
    티스토리 홈 이동
    H
    H
    단축키 안내
    Shift + /
    ⇧ + /

    * 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.