interface Lengthy {
length: number;
}
function countAndPrint<T extends Lengthy>(element: T) {
let descriptionText = "Got No Value";
if(element.length === 1){
descriptionText = "Got 1 element"
} else if(element.length > 1){
descriptionText = "Got" + element.length + "elements");
}
return [element, descriptionText];
}
console.log(countAndPrint("Hello World");
// ["Hello World", "Got 11 elements"]
key값을 넘겨줄 때 사용된다. 따라서 U extends T를 사용하면 된다.
function extractAndConvert<T extends object, U extends keyof T>(obj: T, key: U){
return obj[key];
}
// 뒷쪽에 명확한 키값 name을 적어준다. name: "max"에서 key값은 name이다. 뒷쪽에 age라는 잘못된 key값을 넣어주면 에러가 발생한다.
console.log(extractAndConvert({name: "max"}, "name");
제네릭 class를 사용하는 이유
유연하게 재활용이 가능하다. textStorage 대신 numberStorage를 활용할 때 제네릭 class를 사용할 수 있다.
class DataStorage<T> {
private data: T[] = [];
addItem(item: T){
this.data.push(item);
}
// 효율적으로 removeItem을 작동시키기 위해서는 조건문을 달아주는 것이 좋다.
// ex) 제거대상이 없을 때
removeItem(item: T){
// 제거대상이 없는 경우 -1
if(this.data.indexOf(item) === -1){
return;
}
this.data.splice(this.data.indexOf(item), 1);
}
getItems(){
return [...this.data];
}
}
const textStorage = new DataStorage<string>();
textStorage.addItem("max");
textStorage.addItem("mana");
textStorage.removeItem("max");
console.log(textStorgage(getItem);
// "mana" 만 출력
const objStorage = new DataStorage<object>();
objStorage.addItem({name: "max"});
objStorage.addItem({name: "mana"});
objStorage.removeItem({name: "mana"});
console.log(objStorage.getItems());
// {name: "max"} 출력
종종 사용된다. (typescript에만 존재한다.)
interface Course {
title: string;
description: string;
completeUntil: Date;
}
function createCourseGoal(title: string, description: string, date: Date): Course {
// return {title: title, description: description, completeUntil: date};
// Partial을 활용해 하나씩 집어넣을 수 있다. Course에 모든 type 정의된다. 하지만 한 번에 넣기보다 쪼개서 넣고 싶은 경우, Partial<Course>를 활용해 하나씩 활용이 가능하다.
let result: Partial<Course> = {};
result.title = title;
result.description = description;
result.completeUntil = date;
// 마지막 반환값은 type을 어디서 가져왔는지 as를 통해 명시해야한다.
return result as Course;
}
// 잠금 장치!!
const names: Readonly<string[]> = ["max", "sports"];
// 추가를 막고자 할 때 readonly를 사용하면 된다.
// names.push("mana"); 에러를 발생시킨다. Readonly 때문에 막혔다.
<T> 냐 (number | string | boolean)[] 이냐..
완전 세분화 할 것이냐, 아니면 느슨하게 허용하면서 type을 체크해줄 것이냐 차이가 있다.
물론 느슨하다고 해서 typescript의 장점을 버리는 것이 아니다.
모든 함수 호출마다 다른 타입을 아주 확실히 지정해야하는 경우에는 유니언 타입 (number | string)[]을 사용하는 것이 맞다.
제네릭 타입을 사용하면 제네릭 함수 등에 사용할 때 구체적인 타입의 범위를 좁힐 수 있다.
다른 여러 가지 가능한 타입과 함께 작동하는 타입을 사용하는 경우 제네릭 타입이 효율적이다.