
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"],
};
⇒ key 타입, value 타입, 프로퍼티의 키와 밸류의 규칙만 충족한다면 사용할 수 있는 문법
interface NumberMap {
[key: string]: number;
}
let numberMap1: NumberMap = {
key: -1231,
key2: 123123,
};
⇒ 하나의 타입으로 다양한 객체를 표현할 수 있다.
interface Map<V> {
[key: string]: V;
}
let stringMap: Map<string> = {
key: "value",
};
let booleanMap: Map<boolean> = {
key: true,
};
// 제네릭 타입 별칭
type Map2<V> = {
[key: string]: V;
};
let stringMap2: Map2<string> = {
key: "hello",
};
⇒ 유저 관리 프로그램
⇒ 유저 구분: 학생 유저 / 개발자 유저
⇒ 타입들의 유형을 깔끔하게 분리할 수 있다.
interface Student {
type: "student";
school: string;
}
interface Developer {
type: "developer";
skill: string;
}
interface User<T> {
name: string;
profile: T;
}
function goToSchool(user: User<Student>) {
// if (user.profile.type !== "student") {
// console.log("잘 못 오셨습니다.");
// return;
// }
// 제네릭 인터페이스가 없을 때, 조건식으로 타입 좁히기를 해야하지만,
// 제네릭 인터페이스를 사용하면 코드를 간단하게 하여 타입 좁히기가 가능하다.
const school = user.profile.school;
console.log(`${school}로 등교 완료`);
}
const developerUser: User<Developer> = {
name: "제노",
profile: {
type: "developer",
skill: "typescript",
},
};
// goToSchool(developerUser); // developerUser는 Student 타입 유저에 넣을 수 없기 때문에 오류 발생
const studentUser: User<Student> = {
name: "홍길동",
profile: {
type: "student",
school: "중앙대학교",
},
};
class NumberList {
constructor(private list: number[]) {}
push(data: number) {
this.list.push(data);
}
pop() {
return this.list.pop();
}
print() {
console.log(this.list);
}
}
const numberList = new NumberList([1, 2, 3]);
numberList.pop();
numberList.push(4);
numberList.print();
⇒ string list도 있다고 가정
⇒ 타입을 다 number로 고정시켜놨기 때문에, 모두 바꿔줘야 한다.
⇒ 이를 제네릭 클래스로 해결
class List<T> {
// 범용적으로 사용할 수 있도록 List로 이름 변경
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]);
numberList.pop();
numberList.push(4);
numberList.print();
const stringList = new List(["1", "2"]);
stringList.push("hello");
stringList.print();
const promise = new Promise<number>((resolve, reject) => {
setTimeout(() => {
// resolve(20);
reject("~~ 때문에 실패");
}, 3000);
});
promise.then((response) => {
console.log(response * 10); // 20, number 타입으로 할당
});
promise.catch((err) => {
if (typeof err === "string") {
console.log(err);
}
});
⇒ 프로미스는 제네릭 클래스를 기반으로 타입이 선언되어 있기 때문에, 타입 변수로 비동기 처리 결과값의 타입을 정의해줄 수 있지만, 실패했을 때 타입은 정의해줄 수 없다.
⇒ 따라서 타입 좁히기를 해야한다.
interface Post {
id: number;
title: string;
content: string;
}
// Promise가 클래스 이기 때문에, 타입으로 사용할 수 있다.
// 반환값 타입으로 정의해줄 수 있다.
function fetchPost(): Promise<Post> {
return new Promise((resolve, reject) => {
// new Promise<Post> 이렇게 직접 Post 타입을 정의해줘도 된다.
setTimeout(() => {
resolve({
id: 1,
title: "게시글 제목",
content: "게시글 컨텐츠",
});
}, 3000);
});
}
const postRequest = fetchPost();
postRequest.then((post) => {
post.id;
});