티스토리 뷰
타입스크립트를 제대로 배우지 않고 문서를 보면서 적당히 홈페이지만 개발을 한 적이 있었다. 그 때는 api를 호출하지 않았기 때문에 제네릭을 사용할 일이 없었다. 하지만 api를 호출할 시 비동기적인 코드들과 같이 사용시에는 제네릭이 필수적으로 사용이 된다. 그 중 하나는 Promise 함수 이다.
아래의 함수를 예로 들어보면 간단하게 아이템을 비동기적으로 호출하는 함수이다. 리턴 타입이 일단 제네릭으로 되어 있으며 unknown인 상태이다. promise는 함수 호출 시점에서 await를 사용하느냐 여부에 따라 Pending이 될수도 있고 정상적인 값을 가져올 수도 있다. 그렇기 때문에 리턴 타입을 명확하게 써주어야 한다.
우선 아래와 같이 리턴 타입을 정의해보자. Promise는 타입스크립트에서 이미 제네릭으로 정의가 되어 있다. 그렇기에 리턴타입을 Promise만 적어주면 타입스크립트에서 올바르지 않은 문법이라고 명시해준다.
아래와 같이 고쳐야 한다. Promise<T> 타입처럼 반환될 타입을 명확하게 적어주어야 타입스크립트에서 오류를 표시하지 않는다.
동기적인 코드는 대부분 타입추론이 가능하지만 비동기적인 코드는 타입추론이 되지 않는다. 그렇기에 비동기적인 코드를 작성할 경우에는 타입추론을 명확하게 써주는 것이 중요하다.
interface, generic, enum 등 간단한 예제
interface PhoneNumberDictionary {
[phone: string]: {
num: number;
};
}
interface Contact {
name: string;
address: string;
phones: PhoneNumberDictionary;
}
enum phoneType {
Home = "home",
Office = "office",
Studio = "studio",
}
// api
// TODO: 아래 함수의 반환 타입을 지정해보세요.
function fetchContacts(): Promise<Contact[]> {
// TODO: 아래 변수의 타입을 지정해보세요.
const contacts: Contact[] = [
{
name: "Tony",
address: "Malibu",
phones: {
home: {
num: 11122223333,
},
office: {
num: 44455556666,
},
},
},
{
name: "Banner",
address: "New York",
phones: {
home: {
num: 77788889999,
},
},
},
{
name: "마동석",
address: "서울시 강남구",
phones: {
home: {
num: 213423452,
},
studio: {
num: 314882045,
},
},
},
];
return new Promise((resolve) => {
setTimeout(() => resolve(contacts), 2000);
});
}
// main
class AddressBook {
// TODO: 아래 변수의 타입을 지정해보세요.
contacts: Contact[] = [];
constructor() {
this.fetchData();
}
fetchData(): void {
fetchContacts().then((response) => {
this.contacts = response;
});
}
/* TODO: 아래 함수들의 파라미터 타입과 반환 타입을 지정해보세요 */
findContactByName(name: string): Contact[] {
return this.contacts.filter((contact) => contact.name === name);
}
findContactByAddress(address: string): Contact[] {
return this.contacts.filter((contact) => contact.address === address);
}
findContactByPhone(phoneNumber: number, phoneType: phoneType): Contact[] {
return this.contacts.filter(
(contact) => contact.phones[phoneType].num === phoneNumber
);
}
addContact(contact: Contact) {
this.contacts.push(contact);
}
displayListByName(): string[] {
return this.contacts.map((contact) => contact.name);
}
displayListByAddress(): string[] {
return this.contacts.map((contact) => contact.address);
}
/* ------------------------------------------------ */
}
new AddressBook();