
제네릭은 타입스크립트에서 "값을 타입으로 치환"하는 역할interface Car<T> {
name: string;
color: string;
option: T;
}
// 옵션이 없는 자동차
let car: Car<null> = {
name: "Tesla",
color: "Red",
option: null,
};
// 옵션이 있는 자동차
let car2: Car<{ giftcard: boolean }> = {
name: "Tesla",
color: "Red",
option: { giftcard: true },
};
타입추론 가능
function printValue<T>(value: T): T {
return value;
}
printValue<string>("hello"); // "hello"
printValue<number>(10); // 10
function getFirstElement<T>(arr: T[]): T {
return arr[0];
}
console.log(getFirstElement<number>([1, 2, 4])); // 전송됨
const getFirstElement = function getFirstElement<T>(arr: T[]): T {
return arr[0];
};
const getFirstElement: <T>(arr: T[]) => T = function getFirstElement(arr) {
return arr[0];
};
const getFirstElement: <T>(arr: T[]) => T = (arr) => arr[0];
타입 정의로 함수 타입 지정
type FirstFunc = <T>(arr: T[]) => T;
const getFirstElement: FirstFunc = function getFirstElement(arr) {
return arr[0];
};
인터페이스로 함수 타입 지정
interface FirstFunc {
<T>(arr: T[]): T;
}
const getFirstElement: FirstFunc = (arr) => arr[0];
여러개의 타입 매개변수 사용 가능
function mergObject<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}
console.log(
mergObject<{ name: string }, { age: number }>({ name: "james" }, { age: 10 }) // 함수는 타입추론이 돼서 생략 가능
);
console.log(mergObject<{ name: string }, { gender: string }>({ name: "james" }, { gender: "male" }));
extends 키워드:T extends string은 T가 string 타입이거나 string의 하위 타입이어야 함function getFirstElement<T extends number | string>(arr: T[]): T {
return arr[0];
}
console.log(getFirstElement<number>([1, 2, 4])); // 1
console.log(getFirstElement<string>(["hello", "world"])); // "hello"
// console.log(getFirstElement<boolean>([true, false])); // ❌ 오류
// 조건: 입력값은 { length: number } 속성을 반드시 가져야 함
function getElementsLength<T extends { length: number }>(value: T): number {
return value.length;
}
console.log(getElementsLength("hello")); // 5
console.log(getElementsLength([1, 2, 3])); // 3
// console.log(getElementsLength(10)); // ❌ 오류
제네릭은 여러 타입 조건을 '&'를 사용하여 동시에 적용 가능:
// T는 string과 { length: number } 둘 다 만족해야 함
function printText<T extends string & { length: number }>(text: T) {
console.log(text, text.length);
}
keyofkeyof는 객체의 키를 제네릭으로 추출할 때 사용
//getProperty 함수: 객체와 속성 키를 받아 해당 속성 값을 반환
//조건: obj는 객체여야 하고, key는 obj의 속성 중 하나여야 함
//keyof: 객체의 키를 추출해서 유니온으로 반환
function getProperty<T extends object, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
// 함수 호출: 객체 { name: "james" }에서 "name" 속성 값을 가져옴
//K extends "name"
console.log(getProperty({ name: "james", age: 20 }, "name")); // "james"
//K extends "name" | "age"
console.log(getProperty({ name: "james", age: 20 }, "age")); // 20
function updateProperty<T extends object, K extends keyof T>(obj: T, key: K, value: T[K]): T {
obj[key] = value;
return obj;
}
const car = { brand: "benz", model: "s-class", year: 2020 };
console.log(updateProperty(car, "year", 2024));
// { brand: "benz", model: "s-class", year: 2024 }
두 객체를 병합하는 함수. 반환 타입은 두 객체의 타입을 합친 형태
function mergeObjects<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}
console.log(mergeObjects({ name: "james" }, { age: 10 })); // { name: "james", age: 10 }
입력 객체가 특정 속성을 포함해야 하는 경우, 제네릭을 사용해 타입을 강제 가능
// printUserInfo 함수: Nameable과 Ageable 속성을 모두 가진 객체의 정보를 출력
// 조건: 입력 객체는 반드시 name과 age 속성을 가져야 함
type Nameable = { name: string };
type Ageable = { age: number };
// 함수 정의: Nameable & Ageable 타입을 만족하는 객체를 인자로 받음
//제네릭으로 필수, 제약 타입을 지정 가능
function printUserInfo<T extends Nameable & Ageable>(user: T): void {
console.log(`${user.name}, ${user.age}`);
}
printUserInfo({ name: "james", age: 10 }); // james, 10
출처: 수코딩