제네릭은 타입을 미리 정의하지 않고 사용하는 시점에 원하는 타입을 정의해서 쓸 수 있는 문법입니다.
재사용 가능한 컴포넌트를 만들기 위해 타입스크립트에서 사용하는 도구 중 하나는 제네릭입니다. 즉, 단일 타입이 아닌 다양한 타입에서 작동하는 컴포넌트를 작성할 수 있습니다.
사용자는 제네릭을 통해 여러 타입의 컴포넌트나 자신만의 타입을 사용할 수 있습니다.
function getText(text: any): any {
return text;
}
위의 코드를 살펴보면,
getText
함수는 텍스트를 인수로 넣으면 그대로 반환하는 함수입니다.any
타입을 사용하면 인수의 타입이 어떤 타입이든 상관 없다는 뜻입니다.function getText<Type>(text: Type): Type {
return text;
}
Type
은 사용자가 준 인수의 타입을 캡처하고, 인수와 반환 타입을 같은 타입을 사용할 수 있도록 해줍니다.getText
함수를 실행할 때 아무 타입이나 넘길 수 있습니다.getText<string>('hi'); // hi
getText
함수에 string
타입을 할당한 코드입니다. getText
함수에서 Type
타입 변수가 선언된 곳에 모두 들어갑니다.// 이 함수는 아래처럼 동작합니다.
function getText<string>(text: string): string {
return text;
}
function getText(text: string): string {
return text;
}
getText('hi');
<>
)에 담아 명시적으로 전달하지 않아도 값 'hi'
의 타입을 추론하여 Type
타입 변수에 전달해줍니다.function getText(text: string): string {
return text;
}
function getNumber(num: number): number {
return num;
}
위의 코드를 살펴보면,
getText
함수는 문자열 타입의 텍스트를 인수로 받아 그대로 반환합니다.getNumber
함수는 숫자 타입의 텍스트를 인수로 받아 그대로 반환합니다.any
타입을 사용할 수도 있습니다.function getText(text: any): any {
return text;
}
any
타입을 사용하면 타입을 다양하게 받을 수 있고 코드의 중복을 제거할 수 있습니다.any
를 사용하면 타입스크립트의 장점인 에러 사전 방지가 무색해 질 수 있습니다.function getText<T>(text: T): T {
return text;
}
getText<string>('hi'); // hi
getText<number>(100); // 100
interface Product {
value: string;
selected: boolean;
}
interface Stock {
value: number;
selected: boolean;
}
위의 코드를 살펴보면,
interface Shoppingmall<T> {
value: T;
selected: boolean;
}
// 인터페이스를 각각 작성
const product: Product;
const stock: Stock;
const address: Address;
// 하나의 제네릭 인터페이스 작성
const product: Shoppingmall<string>;
const stock: Shoppingmall<number>;
const address: Shoppingmall<{ city: stirng; zipCode: string }>;
class GetNumber<T> {
value: T;
add: (x: T, y: T) => T;
}
let num = new GetNumber<number>();
num.value = 10;
num.add = function (x, y) {
return x + y;
}
위의 코드를 살펴보면,
GetNumber
클래스에는value
와 add
속성이 있습니다. value
와 add
속성은 모두 넘겨 받은 타입을 사용합니다.number
타입으로 선언하였기 때문에 value
와 add
속성은 number
타입이 됩니다.add
는 함수이므로, x와 y 인자 그리고 반환값이 모두 number
타입으로 선언됩니다.function getText<T>(text: T): T {
return text;
}
getText<string>('hi'); // hi
getText<number>(100); // 100
getText<boolean>(true); // true
위의 코드를 살펴보면,
getText
함수는 제네릭을 이용하여 여러 타입을 받을 수 있는 함수입니다. extends
키워드를 사용하여 타입을 제약할 수 있습니다.function getText<T extends { length: number }>(text: T): T {
return text.length;
}
getText('hi'); // 2
getText([1, 2, 3]); // 3
getText({ title: 'abc', length: 123 }); // 123
getText(10); // Error
extends
키워드로 length 속성을 갖는 타입만 받도록 제약하였습니다.type Developers = keyof { name: string; skill: string; }
// type Developers = "name" | "skill"
위의 코드를 살펴보면,
keyof
키워드는 특정 타입의 키 값을 추출해서 문자열 유니언 타입으로 변환해 줍니다.Developers
타입 별칭에 객체의 키인 name
과 skill
이 유니언 타입으로 선언되었습니다.Developers
타입 별칭은 name
이나 skill
타입을 가집니다.function printKeys<T extends keyof { name: string; skill: string; })>(value: T) {
console.log(value);
}
printKeys('name'); // name
printKeys('skill'); // skill
printKeys('address'); // Error
printKeys(100); // Error
위의 코드를 살펴보면,
extends
키워드와 keyof
키워드를 조합하여 name
이나 skill
타입만을 받도록 제약하였습니다.name
이나 skill
문자열 이외의 문자열이나 타입을 넘기면 에러가 발생합니다.참고
📖 쉽게 시작하는 타입스크립트
🔗https://www.typescriptlang.org/docs/handbook/2/generics.html#handbook-content