반응형
제네릭 인터페이스
제네릭은 인터페이스에도 적용할 수 있다. 다음과 같이 인터페이스에 타입 변수를 선언해 사용하면 된다.
//키페어를 저장하는 객체의 타입을 제네릭 인터페이스로 정의
interface KeyPair<K, V> {
key: K;
value: V;
}
다음과 같이 변수의 타입으로 정의해서 사용할 수 있다.
let keyPair: KeyPair<string, number> = {
key: "key",
value: 0,
};
let keyPair2: KeyPair<boolean, string[]> = {
key: true,
value: ["1"],
};
인덱스 시그니쳐와 함께 사용하기
제네릭 인터페이스는 인덱스 시그니쳐와 함께 사용하면 기존보다 훨씬 유연한 객체 타입을 정의할 수 있다.
interface Map<V> {
[key: string]: V;
}
let stringMap: Map<string> = {
key: "value",
};
let booleanMap: Map<boolean> = {
key: true,
};
- 한개의 타입 변수 V를 갖는 제네릭 인터페이스 Map을 정의했다.
이 인터페이스는 인덱스 시그니쳐로 key의 타입은 string, value의 타입은 V인 모든 객체 타입을 포함하는 타입이다. - 변수 stringMap의 타입을 Map<string> 으로 정의했다.
따라서 V가 string 타입이 되어 이 변수의 타입은 key는 string이고 value는 string인 모든 프로퍼티를 포함하는 객체 타입으로 정의된다. - 변수 booleanMap의 타입을 Map<boolean> 으로 정의했다.
따라서 V가 boolean 타입이 되어 이 변수의 타입은 key는 string이고
value는 boolean인 모든 프로퍼티를 포함하는 객체 타입으로 정의된다.
제네릭 타입 별칭
인터페이스와 마찬가지로 타입 별칭에서도 제네릭이 적용가능하다.
type Map2<V> = {
[key: string]: V;
};
let stringMap2: Map2<string> = {
key: "string",
};
- 제네릭 타입 별칭을 사용할 때에도 제네릭 인터페이스와 마찬가지로 타입으로 정의될 때
반드시 타입 변수에 설정할 타입을 명시해 주어야 한다.
제네릭 클래스
class List<T> {
constructor(private list: T[]) {}
push(data: T) {
this.list.push(data);
}
pop() {
return this.list.pop();
}
print() {
console.log(this.list);
}
}
const numberList = new List([1, 2, 3]);
const stringList = new List(["1", "2"]);
- 클래스의 이름 뒤에 타입 변수를 선언하면 제네릭 클래스가 된다.
- 이 타입 변수는 이제 클래스 내부에서 자유롭게 사용할 수 있다.
- 클래스는 생성자를 통해 타입 변수의 타입을 추론할 수 있기 때문에
생성자에 인수로 전달하는 값이 있을 경우 타입 변수에 할당할 타입을 생략해도 된다.
만약 타입변수의 타입을 직접 설정하고 싶다면 다음과 같이 하면 된다.
class List<T> {
constructor(private list: T[]) {}
(...)
}
const numberList = new List<number>([1, 2, 3]);
const stringList = new List<string>(["1", "2"]);
Promise 사용하기
Promise는 제네릭 클래스로 구현되어 있다. 따라서 새로운 Promise를 생성할 때 다음과 같이 타입 변수에 할당할 타입을 직접 설정해 주면 해당 타입이 바로 resolve 결과값의 타입이 된다.
const promise = new Promise<number>((resolve, reject) => {
setTimeout(() => {
// 결과값 : 20
resolve(20);
}, 3000);
});
promise.then((response) => {
// response는 number 타입
console.log(response);
});
promise.catch((error) => {
if (typeof error === "string") {
console.log(error);
}
});
- 아쉽게도 reject 함수에 인수로 전달하는 값 즉 실패의 결과값 타입은 정의할 수 없다.
그냥 unknown 타입으로 고정되어 있기 때문에 catch 메서드에서 사용하려면 타입 좁히기를 통해 안전하게 사용하는걸 권장한다.
만약 어떤 함수가 Promise 객체를 반환한다면 함수의 반환값 타입을 위해 다음과 같이 할 수 있다.
function fetchPost(): Promise<Post> {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
id: 1,
title: "게시글 제목",
content: "게시글 본문",
});
}, 3000);
});
}
반응형
'Typescript' 카테고리의 다른 글
Typescript | 조건부 타입, infer (0) | 2024.11.04 |
---|---|
Typescript | 타입조작 ( Indexed Access Type, key of & typeof 연산자, mapped Type, Template literal Type ) (3) | 2024.11.04 |
Typescript | 제네릭, 타입 변수 응용, map, forEach 메서드 타입 정의 (1) | 2024.11.03 |
Typescript | 클래스, 접근 제어자, 인터페이스와 클래스 (1) | 2024.11.02 |
Typescript | 인터페이스, 확장, 선언 합치기 (0) | 2024.11.02 |