타입스크립트 - 제네릭

제네릭(generics)은 클래스와 함수에 타입이 고정되는 것을 방지하고 재사용할 수 있는 요소를 선언할 수 있게 합니다. 제네릭은 C#이나 자바와 같은 언어에서 제공됐던 기능으로 타입스크립트 0.9 부터 지원됐습니다.

  • 제네릭의 타입 검사를 컴파일 시간에 진행해 타입 안정성을 보장한다.
  • 캐스팅과 관련한 코드를 제거할 수 있다.
  • 제네릭을 이용하면 제네릭 로직을 이용해 재사용이 가능한 코드를 만들 수 있다.

타입 매개 변수를 통해 타입 안정성을 보장할 수 있다. 타입 안정성은 제네릭 함수명 끝에 선언된 T에 의해 결정됩니다.
T는 타입의 약자로 ‘타입 매개변수’ 또는 ‘제네릭 타입 변수’라 합니다. 타입 매개변수 T 는 타입이 정해져 있지 않은 가상의 타입으로 임의 알파벳이나 단어로 선언해도 좋습니다.

타입 매개 변수 T는 제네릭 함수를 호출 할 때 타입 인수로 타입을 결정합니다. 제네릭 함수의 타입이 결정되는 과정을 ‘타입 바인딩’이라 합니다. 타입 바인딩이 이뤄 지면 타입 안정성이 생깁니다.

캐스팅과 관련한 코드를 제거할 수 있다. 만약 타입 매개변수로 반환 타입의 지정돼 있다면 더는 함수의 반환값에 대해 캐스팅하지 않아도 됩니다.

제네릭 로직을 이용해 재사용할 수 있는 코드를 만들 수 있습니다. 제네릭 로직을 이용하면 타입은 다르지만 같은 로직을 수행하는 재사용성이 좋은 코드를 만들 수 있습니다.

제네릭 함수

타임 매개 변수는 제네릭에서 가장 중요한 요소입니다. 타입 매개변수는 함수 선언에 함수를 제네릭 함수로 변경 할 수 있게 합니다.

1
2
3
4
function concat<T>(strs: T, strs: T) {
return strs + strs2;
}
concat<string>('abc','123');

제네릭 함수의 매개변수 strs가 타입이 결정됐을 때 타입 매개변수와 다른 타입의 인수가 전달되면 타입 오류가 발생합니다.
타입 인수를 전달하면 함수가 불필요한 추론을 하지 않아도 됩니다.

바운드 타입 매개변수를 이용한 T+T 연산시도

타입을 제약 하려면 타입 매개변수는 특정 타입을 상속해야 합니다.
타입 매개변수가 특정 타입으로 묶였다면 해당 타입 매개변수는 T를 바운드 타입 매개변수라고 부릅니다.(유니언 타입을 상속해 선언 할 수도 있습니다.)

1
2
extends string>
extends string | number>

오버로드 함수를 이용한 타입 매개변수 간의 연산

오버로드 함수를 이용하면 T+T 와 같은 타임 매개변수 간에 연산이 가능합니다, 오버로드 함수는 이름만 같고 매개변수의 타입이나 개수가 다르게 선언된 함수를 의미합니다.

제네릭 클래스와 인터페이스

자료구조나 알고리즘은 타입에 의존적이면 범용으로 사용할 수 없습니다. 범용으로 사용할 목적의 자료구조나 알고리즘이 있다면 다양한 타입에 대응하도록 제네릭을 적용해야합니다.
제네릭은 함수처럼 작은 단위뿐아니라, 클래스처럼 큰 단위에서도 적용할 수 있습니다.

제네릭 클래스 선언

제네릭 클래스는 외부로부터 타입을 받아들여 클래스 내부에 입력된 타입을 적용할 수 있는 클래스입니다.

1
2
3
4
5
6
[형식]
class 클래스명 {
getValue(elms: Array, index: number): T {
return elms[index];
}
}

클래스 명 뒤에 타입 매개변수인 를 선언해 줍니다. 는 타입 매개변수이며 매개변수나 반환 타입으로 사용될 수 있습니다.

타입 매개변수에 인터페이스 상속

제네릭 클래스에 전달된 매개변수가 클래스이고 타입 매개변수일때 코드 어시스트를 받지 못할 때가 있다. 이유는 타입 매개변수에 타입이 없기 때문
명시적으로 타입을 선언하려면 처럼 클래스에 대한 인터페이스를 상속해주면 됩니다.

제네릭 클래스를 사용하면 클래스 전역에 걸쳐 타입 매개변수가 적용됩니다. 만약 특정 메서드만을 대상으로 제네릭을 적용하려면 해당 메서드를 제네릭 메서드로 선언하면 됩니다.
메서드 단위로 제네릭을 적용하는 것은 특정 메서드에만 타입 인수를 전달할 수 있으므로 타입의 재활용성이 다소 떨어집니다.
그런데 클래스 단위로 제네릭을 적용하며 클래스 내에 존재하는 불특정 메서드에 대해 일괄적으로 제네릭 메서드로 선언할 수 있어서 더 편리합니다.

제네릭의 여러 활용방법

룩업 타입을 제네릭 클래스에 적용

룩업 타입은 keyof로 속성을 포함하는 대상을 탐색해 유니언 타입처럼 동작합니다.

1
2
3
4
5
6
function  getValue<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
let numberKeys = { one:1, two:2, three:3 };
console.log(getValue(numberKeys, 'one'));
// 1

타입 매개 변수K는 타입 매개변수 T에 의해 정해지는 룩업 타입이 됩니다. 따라서 타입 매개변수 K는 keyof를 이용해 타입 매개변수 T의 속성을 탐색해 하나의 속성만 허용하도록 제약합니다.

인터페이스를 상속해 제네릭 확장하기

인터페이스는 클래스가 구현해야 할 메서드나 프로퍼티를 선언할 수 있습니다. 만약에 구현해야 할 클래스가 제네릭 클래스라면 인터페이스는 제네릭 인터페이스로 선언해야 합니다.
제네릭 인터페이스는 타입 매개변수가 선언된 형태로 선언합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
interface IFilter {
unique(array: Array): Array;
}

class Filter implements IFilter {
unique(array:Array):Array {
return array.filter((v, i, array) => array.indexOf(v) === i);
}
}

let myFilter = new Filter<string>();
let resultFilter = myFilter.unique(['a', 'b', 'c', 'a', 'b']);
console.log(resultFilter);

댓글

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×