*제네릭은 어떠한 클래스 혹은 함수에서 사용할 타입을 그 함수나 클래스를 사용할 때 결정하는 프로그래밍 기법을 말한다.*

Java나 C++등의 정적 타입 언어에서는 함수 및 클래스를 선언하는 시점에서 매개변수 혹은 리턴 타입을 정의해야하기 때문에 기본적으로는 특정 타입을 위해 만들어진 클래스나 함수를 다른 타입을 위해 재사용할 수가 없다. 때문에 제네릭을 통해 함수와 클래스의 범용적인 사용을 가능케 한다.

[ 타입 재사용에 용이한 함수 제네릭 / 제네릭을 사용하는 이유 ]

*// 일반적인 타입 정의
// 함수 호출 시 number 타입만 사용이 가능하다.
// Bad*
function checkNotNullBad(arg: number | null): number {
  if (arg == null) {
    throw new Error('not valid number!');
  }
  return arg;
}

*// 유동적인 타입 정의*
*// 함수 호출 시 여러 타입사용은 가능하지만 any 를 사용하는건 좋지 않다.
// Very Bad*
function checkNotNullAnyBad(arg: any | null): any {
  if (arg == null) {
    throw new Error('not valid number!');
  }
  return arg;
}
const result = checkNotNullAnyBad(123);

*// 유동적인 타입 정의
// 함수 호출 시 사용된 값(인수)에 의해 타입이 정의되며, 타입이 보장된다.
// Good*
function checkNotNull<T>(arg: T | null): T {
  if (arg == null) {
    throw new Error('not valid number!');
  }
  return arg;
}
const number = checkNotNull(123);
*// 또는 const number = checkNotNull<number>(123);*

const boal: boolean = checkNotNull(true);
*// 또는 const boal: boolean = checkNotNull<boolean>(true);*