프로미스에 제네릭 문법을 사용할 경우의 이점을 아래 예시와 함께 살펴보겠습니다.
예시
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject("성공!");
}, 2000);
});
변수 promise는 비동기 함수 setTimeout이 성공적으로 작동하면 resolve에 인수로 문자 데이터를 전달하는 Promise 인스턴스를 할당받고 있습니다.
변수 promise는 프로미스 타입으로 명시되어 있으며 제네릭 문법을 사용하여 unknown 타입이 명시되어 있습니다.
이는 프로미스가 결국에는 무언가를 성공(resolve)시키기 때문이며 unknown 타입의 명시는 전달하는 문자 데이터로 무엇을 성공시키고자 하는지 타입스크립트가 제대로 이해하지 못하기 때문입니다.
const promise: Promise<string> = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("성공!");
}, 2000);
});
때문에 해당 프로미스가 문자 데이터를 반환한다고 위와 같이 명확하게 타입을 명시해 줍니다.
여기서 짚고 넘어갈 부분은 타입은 프로미스로 명시되어 있지만, 프로미스는 배열처럼 다른 타입과 함께 작동한다는 점입니다. 배열은 특정 타입의 데이터를 지정하기 때문에 다른 타입과 함께 사용됩니다. 결국 프로미스는 어떤 타입의 테이터를 반환하는 것이므로 다른 타입과 함께 작동하며, 위의 예시 코드의 경우 프로미스는 결국 문자열을 반환합니다.
왜 위와 같이 프로미스에 추가적인 타입을 명시해주는 것이 유용할까라고 생각할 수 있습니다. 예시 코드를 추가로 살펴보겠습니다.
const promise: Promise<any> = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("성공!");
}, 2000);
});
promise.then((data) => {
data.split("");
});
변수 promise는 앞서 작성한 코드와 동일하며 제네릭 문법 안의 타입만 any로 변경되어 있습니다.
*제네릭 문법에 any를 사용할 경우 제네릭 문법을 사용하지 않은 것과 동일합니다.
위의 코드는 promise가 resolve 시 문자열을 반환하는 것을 기대하고 반환 값에 문자열 메서드는 split을 사용하고 있습니다.
이때 프로미스의 resolve에 숫자 데이터가 전달되도록 변경해도 타입 에러가 발생하지 않으며, 이는 제네릭 문법에 any 타입을 명시했기 때문에 타입스크립트의 도움을 받지 못하기 때문입니다.
const promise: Promise<string> = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(10); // 타입 에러 발생
}, 2000);
});
promise.then((data) => {
data.split("");
});
제네릭 문법에 프로미스가 반환하는 값의 타입을 명확하게 명시해주면 해당 문제를 해결할 수 있습니다.
위의 경우 프로미스가 반환하는 값의 타입이 string이라고 명시했게 때문에 resolve의 인수는 문제 데이터가 전달되어야 하는데 숫자 데이터를 전달했기 때문에 타입 에러가 발생하게 됩니다.
const promise: Promise<number> = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(10);
}, 2000);
});
promise.then((data) => {
data.split(""); // 타입 에러 발생
});
추가로 프로미스가 반환하는 값의 타입을 위와 같이 number로 명시해주게 되면 코드 하단의 promise가 반환하는 데이터에 문자 메서드 사용 시 타입 에러가 발생하게 됩니다.
이렇게 프로미스의 반환타입을 제네릭 문법을 사용하여 명시해주면 타입스크립트는 보다 나은 타입의 안정성을 확보할 수 있게 해 줍니다.
'TypeScript' 카테고리의 다른 글
map 타입, condition 타입 (0) | 2023.01.14 |
---|---|
union 타입과 intersection 타입 (0) | 2023.01.06 |
인터페이스와 클래스 (0) | 2023.01.05 |
열거형 타입 (Enum) (0) | 2023.01.04 |
타입 스크립트 구성 옵션 (0) | 2023.01.03 |