728x90
타입스크립트 제네릭 정리

❓상황

타입스크립트 기본 개념 중 하나인 제네릭 정리

 

📖 제네릭이란?

재사용성이 높은 컴포넌트를 만들 때, 자주 활용되는 기법이다.

특히, 한가지 타입보다는 여러가지 타입이 동작하는 컴포넌트를 만들 때 주로 활용된다.

 

🧮 정리

기본 문법

제네릭은 변수명 뒤쪽에 꺽쇠(<>)와 타입을 넣으면 된다.

이때, 타입은 string, number가 아닌 제네릭 타입 변수를 넣어준다. 주로 알파벳 T를 사용한다.

그리고 제네릭 타입변수 T를 일반 타입(number, string )처럼 활용하면 된다.

 

제네릭 함수

만약 함수의 인자가 어떤 타입이 들어올지 몰라 any 타입으로 지정한다면,

함수의 return 타입도 또한 any 타입이다.

function foo(name: any): any {
    return `Hello, ${name}`
}

foo<string>('이동규'); // 이동규 (any)
foo<number>(123); // 123 (any)

 

함수의 인자에 따라 return 값이 동일하게 만들기 위해서는 제네릭 타입변수를 활용할 수 있다.

function foo<T>(input: T): T {
    return input
}

foo<string>('이동규'); // 이동규 (string)
foo<number>(123); // 123 (number)

 

함수에서는 인자값이 한가지 타입으로 정해지지 않았을때, 제네릭 타입변수를 활용한다.

 

제네릭 클래스

클래스명 뒤에 꺽쇠와 제네릭 타입변수를 작성하고, 타입 변수를 사용하면 된다.

class List<T> {
  private _data: T[];

  constructor (data: T[]) {
      this._data = data
  }
  
  add(item: T) {
  	this._data = [...this._data, item];
  }
  
  print() {
  	console.log(this._data);
  }
}

const list1 = new List<number>([1,2,3]);
list1.add(4);
list1.print(); // this._data = [1,2,3,4];

const list2 = new List<string>([]);
list2.add('lee'); 
list2.print(); // this._data = ['lee'];

const list3 = new List<string | number>([1,2,3]);
list3.add('asd'); 
list3.print(); // this._data = [1,2,3,'asd'];

 

제네릭 인터페이스

인터페이스 타입을 받아 사용할때 뒤에 꺽쇠와 제네릭 타입변수를 작성하고, 타입 변수를 사용하면 된다.

interface fooType<T, U> {
    a: T,
    b: U
}

 

제네릭 컨벤션

제네릭 타입 변수를 여러개 쓸 경우 T, U, V, W, X, Y, Z 알파벳 순서로 사용한다.

 

⭐제네릭 제약조건

만약, 제네릭을 사용한 함수의 인자값의 length라는 property에 접근한다고 해보자

length라는 프로퍼티는 number 숫자를 반환하는데, 제네릭 타입 변수에는 

function foo<T> (input: T) {
    console.log(input.length)  // error! T doesn't have .length
}

 

length 프로퍼티를 갖는 타입을 작성해줘야한다.

방법은 제네릭 타입 변수를 extends 키워드를 이용하여, 확장해주면 된다.

function foo<T extends {length: number}> (input: T) {
    console.log(input.length)  // error! T doesn't have .length
}

foo<number[]>([1,2,3,4]);          // 4
foo<string>('string');             // 6

// 타입 추론을 활용해도 된다!
foo('string');                     // 6

 

객체의 property에 접근하기위해서는 타입추론을 이용하거나 객체의 모든 property에 타입을 지정해줘야 에러가 발생하지않는다.

function foo<T> (input: T) {
    console.log(input.length)  // error! T doesn't have .length
}

foo({ length: 100, value: 'hi' });
foo<{ value: string, length: number }>({ length: 100, value: 'hi' });

 

객체의 경우 제네릭을 활용할 수 있는 것이 많은데,

객체의 property에 접근하기 전 제네릭 타입 변수를 이용하여, 객체의 property 접근을 제한할 수 있다.

function getProperty<T, O extends keyof T>(obj: T, key: O) {
  return obj[key];  
}

getProperty({ a: 1, b: 2, c: 3 }, "a");
getProperty({ a: 1, b: 2, c: 3 }, "z"); // error: "z"는 "a", "b", "c" 속성에 해당하지 않습니다.

 

참고

https://joshua1988.github.io/ts/intro.html

복사했습니다!