
function func(value: string) {
return value;
}
func(10);
func(true);
func(10);
func(true);
⇒ 이렇게 number, boolean을 넣고싶을 때?
⇒ 이럴 때 사용하면 좋은 것이 제네릭
function func<T>(value: T): T {
return value;
}
let num = func(10); // number 타입으로 추론됌
let bool = func(true); // boolean 타입으로 추론됌
let str = func("string"); // string 타입으로 추론됌
let arr2 = func<[number, number, number]>([1, 2, 3]);
// 튜플 타입으로 할당하기. T의 타입은 튜플로 할당됌.
function swap<T>(a: T, b: T) {
return [b, a];
}
const [a, b] = swap("1", 2); // 첫 번째 매개변수를 string으로 정의하면 오류가 발생
// T는 string 타입으로 할당 -> 2는 number 타입, 이미 T는 string 타입으로 할당됌
// number와 string 타입이 달라서 오류 발생
// 이럴 때는 타입 변수를 2개를 사용하면 됌
해결방법
function swap<T, U>(a: T, b: U) {
return [b, a];
}
const [a, b] = swap("1", 2);
function returnFirstValue<T>(data: T[]) {
return data[0];
}
let num = returnFirstValue([0, 1, 2]);
let str = returnFirstValue([1, "hello", "mynameis"]);
// number | string 유니온 타입으로 추론됌
⇒ 첫 번째 요소를 바꾸더라도 number 타입으로만 추론이 됐으면 할 때
function returnFirstValue<T>(data: [T, ...unknown[]]) {
return data[0];
}
let num = returnFirstValue([0, 1, 2]);
let str = returnFirstValue([1, "hello", "mynameis"]);
T는 number로 할당됌
function getLength(data: any) {
return data.length;
}
let var1 = getLength([1, 2, 3]); // 3
let var2 = getLength(["12345"]); // 5
let var3 = getLength({ length: 10 }); // 10
let var4 = getLength(10); // 오류 발생(x)
// var1~3처럼 length가 있는 것은 받고, var4처럼
// length가 존재하지 않는 것은 받지 않는 법
⇒ var1~3처럼 length가 있는 것은 받고, var4처럼 lenght가 존재하지 않는 것은 받지 않는 방법
해결 방법
function getLength<T extends { length: number }>(data: T) {
return data.length;
}
let var1 = getLength([1, 2, 3]); // 3
let var2 = getLength(["12345"]); // 5
let var3 = getLength({ length: 10 }); // 10
let var4 = getLength(10); // 오류 발생
⇒ number 타입의 lenght를 가지고 있는 객체를 확장하는 타입으로 T를 제한
map 예시
const arr = [1, 2, 3];
const newArr = arr.map((it) => it * 2);
// [2, 4, 6];
map 정의
function map<T>(arr: T[], callback: (item: T) => T) {
let result = [];
for (let i = 0; i < arr.length; i++) {
result.push(callback(arr[i]));
}
return result;
}
map(arr, (it) => it * 2); // number 타입으로 추론됌
map(["hi", "hello"], (it) => it.toUpperCase()); // string 타입으로 추론됌
map(["hi", "hello"], (it) => parseInt(it)); // 오류발생
// 콜백 함수의 반환값이 number가 됌
// arr 매개변수에 string 배열 타입이 들어감
// T는 string 타입이 됌
// 콜백함수의 매개변수의 타입도 string 타입이 됌
// 콜백함수의 반환값 타입도 string이 됌
// 하지만, parseInt 때문에 number 타입으로 전달되서 매치가 안되서 오류가 발생
문제 해결
// 제네릭 타입 변수를 하나 말고, 2개 타입 변수를 써주면 된다.
function map<T, U>(arr: T[], callback: (item: T) => U) {
let result = [];
for (let i = 0; i < arr.length; i++) {
result.push(callback(arr[i]));
}
return result;
}
map(arr, (it) => it * 2); // number 타입으로 추론됌
map(["hi", "hello"], (it) => it.toUpperCase()); // string 타입으로 추론됌
map(["hi", "hello"], (it) => parseInt(it)); // 오류발생
// arr에 string 배열 타입이 들어감 => T = string타입
// 콜백함수의 item T도 string 타입
// 이때 콜백함수의 반환값의 타입은 number 타입이 됌.
// U의 타입은 이때 추론이 되어 number 타입이 됌.
const arr2 = [1, 2, 3];
arr2.forEach((it) => console.log(it));
function forEach<T>(arr: T[], callback: (item: T) => void) {
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
}
forEach(arr2, (it) => {
console.log(it.toFixed());
});
forEach(["123", "456"], (it) => {
it;
});