제네릭은 재사용성이 높은 컴포넌트를 만들 때 자주 활용된다. 즉, 특정 타입에 고정되지 않고 여러 타입에서 동작할 수 있는 컴포넌트를 생성하는데 사용된다.
마치 타입을 함수의 변수처럼 유동적으로 지정하여 사용하는 것을 뜻한다.
제네릭은 선언 시점이 아닌, 생성 시점에 타입을 명시하여 다양한 타입의 사용을 가능케 한다.
const getValue1 = (value: number): number => { return value; }; console.log(getValue1(15)); // 15 // const getValue2 = (value: string): string => { return value; }; console.log(getValue2("value")); // value
위 함수는 value
라는 인자를 받아 리턴하는 함수이다.
로직은 똑같지만 단지 타입이 다르다는 이유로 함수를 재생성하거나, 혹은 기존 함수의 타입을 변경해야하는 비효율적인 점이 존재한다.
const getValue = function (value: any): any { return value; };
// function expression const getValue = function <T>(value: T): T { return value; }; // // arrow function const getValue = <T>(value: T): T => { return value; }; // console.log(getValue<string>("value")); // value console.log(getValue("value")); // value // console.log(getValue<number>(100)); // 100 console.log(getValue(100)); // 100
제네릭을 사용할 경우, 타입을 인자처럼 사용할 수 있다. 즉 <T>
부분이 마치 타입만을 위한 매개변수처럼 작용한다고 생각하면 쉽다. 호출부를 확인해보면 타입 부분에 <number>
라고 들어가게 되며, 이때 T
의 자리는 모두 number
가 된다.
함수를 호출하는 방법은 함수명 뒤에 <>
안에 타입을 기입하는 방법과, 단순히 인자만 전달하는 방법이 있다. 보통 두 번째 방법을 많이 사용하나 복잡한 로직에서 타입 추정이 힘들시 첫번째 방법을 사용하면 된다.
class Person<T, N> { constructor(public name: T, protected gender: T, private age: N) {} getAge(): N { return this.age; } } const person = new Person("yongmin", "male", 30); console.log(person); // Person { name: 'yongmin', gender: 'male', age: 30 } console.log(person.getAge()); // 30
<T>
를 붙이며, 인스턴스를 생성할 때 어떤 들어갈 지 지정하면 된다.function text<T>(text: T): T { console.log(text.length); // Property 'length' does not exist on type 'T'. return text; }
length
라는 속성에 접근하고자 할 경우, 타입을 알 수 없으므로 에러가 발생한다.interface Length { length: number; } function text<T extends Length>(text: T): T { console.log(text.length); return text; }
extends
를 통해 제네릭에게 타입 힌트를 주어 해당 속성에 접근을 가능케 할 수 있다.const obj = { name: "yongmin", age: 20, }; function getValue<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } console.log(getValue(obj, "name")); // yongmin
위처럼, 제네릭을 사용하여 객체에 있는 속성들에게만 접근하도록 지정할 수 있다.
K
라는 타입은, T
라는 타입의 키값으로부터 상속받는다.
리턴 값은 T
타입의 객체에서 K
타입 key의 value
이다.