타입스크립트 기초 제네릭 제약 조건
타입스크립트 제네릭( Typescript Generic )은 extends 키워드를 사용하여 제약 조건을 설정할 수 있다.
타입스크립트 객체의 프로퍼티, 인터페이스, keyof 등을 활용하여 타입 오류를 방지한다.
타입스크립트의 제네릭은 다양한 타입을 하나의 함수나 클래스에서 재사용할 수 있도록 지원하는 기능이다.
만약, 제네릭 기능에도 제약 조건(Generic Constraints)을 추가하고자 한다면, extends 키워드를 사용할 수 있다.
extends 키워드를 사용하여 타입스크립트 제너릭을 사용하면, 타입 매개변수가 반드시 충족해야 하는 구조나 타입을 설정할 수 있다.
![]() |
| 타입스크립트 기초 제네릭 제약 조건 |
⊙ 타입스크립트 제네릭 제약 조건 기본 문법
타입스크립트 제네릭 제약 조건( Typescript Generic Constraints)은 제네릭 타입 매개변수에 허용되는 타입의 범위를 제한할 수 있으며 키워드는 extends 를 사용한다.
기본 문법은 다음과 같다.
function example<T extends string>(value: T): T {
return value;
}위 코드의 T extends string 부분을 보자.
여기서 extends는 제네릭 타입에 대한 제약을 표현한다.
타입 매개변수 T 는 무조건 string 타입에 할당 가능한 타입임을 제한한다.
사용 방법은 다음과 같다.
example("Hello"); // 정상
example("TypeScript"); // 정상
// example(123); // 타입 오류숫자 123은 string에 할당할 수 없으므로 타입 검사 과정에서 오류가 발생한다.
![]() |
| 타입스크립트 제네릭 제약 조건 기본 문법 |
⊙ 제네릭 length 프로퍼티 제한
타입스크립트의 모든 타입에 length가 존재하는 것이 아니기 때문에, 특정 프로퍼티를 사용하려면 해당 프로퍼티가 존재한다는 사실을 타입 시스템에 알릴 필요가 있다.
function getLength<T extends { length: number }>(
value: T
): number {
return value.length;
}
console.log(getLength("Hello"));
console.log(getLength([10, 20, 30]));T extends { length: number }는
length 프로퍼티가 존재하고 그 타입이 number인 값만 허용한다는 의미다.
숫자 타입에는 요구된 length 프로퍼티가 없으므로 타입 검사에서 오류가 발생한다.
위의 코드에 대한 결과는 다음과 같다.
![]() |
| 제네릭 length 프로퍼티 제한 코드 실행 결과 |
![]() |
| 제네릭 length 프로퍼티 제한하기 |
⊙ 인터페이스를 활용한 제네릭 제약 조건
타입스크립트 제네릭 제약 조건은 인터페이스(Interface)를 이용할 수 있다.
인터페이스에 필수 프로퍼티를 정의하고 제네릭의 extends에 지정하면 된다.
interface User {
id: number;
name: string;
}
function printUser<T extends User>(user: T): void {
console.log(user.id);
console.log(user.name);
}
printUser({
id: 1,
name: "Kim"
});T extends User는
전달하는 값이 User 인터페이스에서 요구하는 id와 name 프로퍼티를 가지고 있어야 한다는 의미다.
위의 코드에 대한 결과는 다음과 같다.
![]() |
| 인터페이스를 활용한 제네릭 제약 조건 코드 실행 결과 |
![]() |
| 인터페이스를 활용한 제네릭 제약 조건 |
⊙ keyof 사용 제네릭 제약 조건
keyof는 객체 타입의 프로퍼티 키를 타입으로 추출하는 연산자다.
제네릭의 extends와 결합하면
객체에 실제로 존재하는 프로퍼티 이름만 전달하도록 제한할 수 있다.
코드를 보자.
function getProperty<T, K extends keyof T>(
obj: T,
key: K
): T[K] {
return obj[key];
}
const user = {
id: 1,
name: "Kim",
age: 25
};
console.log(getProperty(user, "name"));
console.log(getProperty(user, "age"));위 코드에서 각 표현의 의미는 다음과 같다.
- T
- 전달한 객체의 타입이다.
- keyof T
- 객체 타입의 프로퍼티 키 타입을 추출한다.
- K extends keyof T
- 전달할 키를 객체에 존재하는 키로 제한한다.
- T[K]
- 해당 키에 대응하는 프로퍼티의 타입을 나타낸다.
위의 코드에 대한 결과는 다음과 같다.
![]() |
| keyof 사용 제네릭 제약 조건 코드 실행 결과 |
![]() |
| keyof 사용 제네릭 제약 조건 |
⊙ 여러 개의 제네릭 제약 조건 사용
타입 매개변수에
여러 조건을 동시에 제약 조건을 사용하려면
교차 타입(Intersection Type)을 사용할 수 있다.
교차 타입은 & 연산자로 표현하며, 지정한 타입의 요구사항을 모두 충족하도록 한다.
interface HasId {
id: number;
}
interface HasName {
name: string;
}
function printInfo<T extends HasId & HasName>(
value: T
): void {
console.log(value.id);
console.log(value.name);
}
printInfo({
id: 10,
name: "Lee"
});T extends HasId & HasName은
HasId와 HasName에서 요구하는 프로퍼티를 모두 충족해야 한다는 의미이며,
id와 name이 모두 필요하다.
위의 코드를 실행해 보자. 결과는 다음과 같다.
![]() |
| 여러 개의 제네릭 제약 조건 코드 실행 결과 |
![]() |
| 여러 개의 제네릭 제약 조건 사용 |
⊙ 제네릭 클래스에 제약 조건 사용
제네릭 제약 조건은 함수뿐만 아니라 클래스(Class)에서도 사용할 수 있다.
클래스의 타입 매개변수에 extends를 적용하면 지정한 조건을 충족하는 타입만 사용할 수 있다.
interface Entity {
id: number;
}
class Repository<T extends Entity> {
private items: T[] = [];
add(item: T): void {
this.items.push(item);
}
getAll(): T[] {
return this.items;
}
}
interface Product {
id: number;
name: string;
}
const productRepository = new Repository<Product>();
productRepository.add({
id: 1,
name: "Keyboard"
});
console.log(productRepository.getAll());Repository<T extends Entity>는
타입 매개변수 T가 최소한 id: number 프로퍼티를 갖도록 제한한다.
Product 인터페이스에는 id가 존재하므로 제약 조건을 충족한다.
위의 코드를 실행한 결과는 다음과 같다.
![]() |
| 제네릭 클래스에 제약 조건 코드 실행 결과 |
![]() |
| 제네릭 클래스에 제약 조건 사용 |












댓글
댓글 쓰기