타입을 고정된 값으로 명시하는 것이 아니라 변수를 통해 상황에 따라
변할 수 있는 타입으로 지정할 수 있다.
제네릭 타입 이름은 보통 대문자 하나로만 작성한다.
일반적으로 제네릭 타입을 명시할 때<T>로 명시한다.
function print<T>(text:T): T {
return text;
}
console.log(print(1));
console.log(print('안녕하세요'));
보통 제네릭은 어떤 타입이든 들어올 수 있다.
제네릭을 통해 유연한 데이터를 반환할 수 있지만 때로는 함수에 따라
입력값을 제한하는 경우도 있다. 이때 제네릭 제약 조건을 이용한다.
제네릭 제약 조건은 extends 키워드를 통해 적용되는 타입 종류를 제한할 수 있다.
💡 제네릭 extends vs 인터페이스/클래스 extends
클래스의 extends는 상속의 의미로 '확장'의 정의를 가지는 반면, 제네릭의 extends는 '제한'의 의미를 가진다는 차이점이 있다.따라서<T extends K>형태 제네릭은 T가 K에 할당 가능해야 한다 라고 정의하면 된다.
제네릭을 통해 문자열 타입만 제한한 경우, 숫자 타입이 들어가면
컴파일 오류가 발생한다.
function print<T extends string>(text:T): T {
return text;
}
console.log(print(1)); // Argument of type 'number' is not assignable to parameter of type 'string'.
console.log(print('안녕하세요'));
하나의 함수에서 제네릭은 여러개 지정해 사용할 수 있다.
각 매개변수마다 다른 제네릭 타입 조건 제한할 수 있다.
function print<T extends string,K extends number>(text1:T,text2:K): void {
console.log(text1,text2);
}
console.log(print('1',1)); // "1", 1
console.log(print('안녕하세요',0)); // "안녕하세요", 0
객체의 특정 key 값을 가져오는 함수를 작성해보자.
객체의 key 값을 가져올 때 key는 전달받은 객체의 key 들중 하나여야 한다.
keyof T는 객체 T에 있는 key들 중 하나로 선언한다는 의미이다.
function getValue<T, K extends keyof T>(obj: T, key: K):T[K]{
return obj[key];
}
- keyof T = T(object) 속 키(key) 이름들(string)
- T[K] = T(object)의 K[key] 값 자체 타입