제네릭이란?
타입을 미리 정의하지 않고 사용하는 시점에 원하는 타입을 정의해서 사용할 수 있는 문법. 마치 함수의 파라미터와 같은 역할을 한다.
기본 문법
function getText<T>(text: T): T {
return text;
}
getText<string>("hi");
T라고 선언된 모든 부분에서 string 타입이 들어간다.
다음과 같이 선언된 것과 같다.
function getText(text: string): string {
return text;
}
마찬가치로 boolean, number, object 등 어느 타입이든 getText() 함수를 호출할 때 타입을 지정이 가능하다.
제네릭을 사용하는 이유
- 중복된 타입 코드의 문제점
- 같은 기능을 하는 함수에서 타입만 다를 경우 각각의 타입을 정의하여 여러 함수를 만들어줘야 하는 중복을 줄여준다
- any를 쓰면 되지 않을까?
- any를 사용하면 타입스크립트의 장점이 사라짐
- 코드 자동완성이나 에러의 사전 방지 혜택을 받지 못함
function getText<T>(text: T): T {
return text;
}
getText<number>(100);
getText<string>("hi");
getText<number>("hello"); // 타입 에러 발생
function getAny(text: any): any {
return text.toString();
}
getAny("hi");
getAny(100);
getAny(true); // 실행과정에서 에러
인터페이스에서 제네릭 사용하기
// 이러한 인터페이스가 있다고 하게 되면 타입 코드가 많아지고 관리 포인트가 어려워 번거로운 작업이 된다.
interface ProdoctDropdown {
value: string;
selected: boolean;
}
interface StockDropdown {
value: number;
selected: boolean;
}
interface AddressDropdown {
value: { city: string; zipCode: string };
selected: boolean;
}
// 인터페이스 이름 오른쪽에 <T>를 붙이고 내부 속성 중 제네릭으로 받은 타입을 사용할 곳을 T로 연결
interface Dropdown<T> {
value: T;
selected: boolean;
}
let product: Dropdown<string>;
let stock: Dropdown<number>;
let address: Dropdown<{ city: string; zipCode: string }>
제네릭의 타입 제약
extends를 사용한 제약
모든 타입이 아니라 몇 개의 타입만 제네릭으로 받고 싶을 때
function embraceEverything<T extends string>(thing: T): T {
return thing;
}
embraceEverything<string>("hi");
embraceEverything<number>(1000); // 에러 발생
// length 속성을 갖는 타입만 취급하고 싶을 때
// string, array, object
function getLength<T extends {length: number}>(value: T) {
return value.length;
}
getLength("hi");
getLength(["a","b","c"];
getLength(100); // 타입 에러 발생
keyof를 사용한 제약
특정 키 값을 타입 지정
function printKeys<T extends keyof { name: string; skill: string }>(value: T) {
console.log(value);
}
printKeys("hello") // 타입 에러
printKeys({ name: "mk", skill: "ts"});
제네릭 타입을 사용할 때 주의할 점
아래의 코드에선 타입 추론이 되지 않고 어떤 타입이 들어올지 모르기 때문에 함수 내부에서 에러 발생.
위에서 설명 extends를 활용한 힌트가 필요함
function printLength<T>(text: T) {
console.log(text.length);
}
printLength<string>("hello");
function getLength<T extends {length: number}>(value: T) {
return value.length;
}
getLength<string>("hello");
// 제네릭으로 받은 타입을 배열 형태로 정의하는 방법
function printLength<T>(text: T[]) {
console.log(text.length);
}
printLength<number>([100]);
printLength<boolean>([true, false]);
'TYPESCRIPT' 카테고리의 다른 글
[Typescript] 타입 단언 (Type Assertion) (0) | 2024.09.23 |
---|---|
[Typescript] Enum(이넘) (0) | 2024.07.16 |
[Typescript] 인터페이스(interface)[2] (0) | 2024.07.12 |
[Typescript] 인터페이스란? (interface)[1] (0) | 2024.07.09 |
[Typescript] 타입 종류 (0) | 2024.06.11 |
제네릭이란?
타입을 미리 정의하지 않고 사용하는 시점에 원하는 타입을 정의해서 사용할 수 있는 문법. 마치 함수의 파라미터와 같은 역할을 한다.
기본 문법
function getText<T>(text: T): T {
return text;
}
getText<string>("hi");
T라고 선언된 모든 부분에서 string 타입이 들어간다.
다음과 같이 선언된 것과 같다.
function getText(text: string): string {
return text;
}
마찬가치로 boolean, number, object 등 어느 타입이든 getText() 함수를 호출할 때 타입을 지정이 가능하다.
제네릭을 사용하는 이유
- 중복된 타입 코드의 문제점
- 같은 기능을 하는 함수에서 타입만 다를 경우 각각의 타입을 정의하여 여러 함수를 만들어줘야 하는 중복을 줄여준다
- any를 쓰면 되지 않을까?
- any를 사용하면 타입스크립트의 장점이 사라짐
- 코드 자동완성이나 에러의 사전 방지 혜택을 받지 못함
function getText<T>(text: T): T {
return text;
}
getText<number>(100);
getText<string>("hi");
getText<number>("hello"); // 타입 에러 발생
function getAny(text: any): any {
return text.toString();
}
getAny("hi");
getAny(100);
getAny(true); // 실행과정에서 에러
인터페이스에서 제네릭 사용하기
// 이러한 인터페이스가 있다고 하게 되면 타입 코드가 많아지고 관리 포인트가 어려워 번거로운 작업이 된다.
interface ProdoctDropdown {
value: string;
selected: boolean;
}
interface StockDropdown {
value: number;
selected: boolean;
}
interface AddressDropdown {
value: { city: string; zipCode: string };
selected: boolean;
}
// 인터페이스 이름 오른쪽에 <T>를 붙이고 내부 속성 중 제네릭으로 받은 타입을 사용할 곳을 T로 연결
interface Dropdown<T> {
value: T;
selected: boolean;
}
let product: Dropdown<string>;
let stock: Dropdown<number>;
let address: Dropdown<{ city: string; zipCode: string }>
제네릭의 타입 제약
extends를 사용한 제약
모든 타입이 아니라 몇 개의 타입만 제네릭으로 받고 싶을 때
function embraceEverything<T extends string>(thing: T): T {
return thing;
}
embraceEverything<string>("hi");
embraceEverything<number>(1000); // 에러 발생
// length 속성을 갖는 타입만 취급하고 싶을 때
// string, array, object
function getLength<T extends {length: number}>(value: T) {
return value.length;
}
getLength("hi");
getLength(["a","b","c"];
getLength(100); // 타입 에러 발생
keyof를 사용한 제약
특정 키 값을 타입 지정
function printKeys<T extends keyof { name: string; skill: string }>(value: T) {
console.log(value);
}
printKeys("hello") // 타입 에러
printKeys({ name: "mk", skill: "ts"});
제네릭 타입을 사용할 때 주의할 점
아래의 코드에선 타입 추론이 되지 않고 어떤 타입이 들어올지 모르기 때문에 함수 내부에서 에러 발생.
위에서 설명 extends를 활용한 힌트가 필요함
function printLength<T>(text: T) {
console.log(text.length);
}
printLength<string>("hello");
function getLength<T extends {length: number}>(value: T) {
return value.length;
}
getLength<string>("hello");
// 제네릭으로 받은 타입을 배열 형태로 정의하는 방법
function printLength<T>(text: T[]) {
console.log(text.length);
}
printLength<number>([100]);
printLength<boolean>([true, false]);
'TYPESCRIPT' 카테고리의 다른 글
[Typescript] 타입 단언 (Type Assertion) (0) | 2024.09.23 |
---|---|
[Typescript] Enum(이넘) (0) | 2024.07.16 |
[Typescript] 인터페이스(interface)[2] (0) | 2024.07.12 |
[Typescript] 인터페이스란? (interface)[1] (0) | 2024.07.09 |
[Typescript] 타입 종류 (0) | 2024.06.11 |