[TypeScript-입문] 11.제네릭(Generic)


제네릭(Generic)에 대한 포스팅이다.


제네릭(Generic)이란?

아래는 자바에서 말하는 제네릭 개념이다. 타입스크립트에서의 제네릭도 동일한 개념으로 생각해도 된다.

  • 자바에서 제네릭(generic)이란 데이터의 타입(data type)을 일반화하는(generalize) 것을 의미
  • 타입을 미리 정의하면 컴파일 시에 타입을 체크(type check)해 주는 기능
  • 런타임(실행 시)에 발생하는 에러를 예방하기 위해서 먼저 컴파일때 타입 체크를 하는 것.
  • 객체의 타입 지정함으로서 이외의 타입을 제한하기에 프로그래머의 형변환 실수를 컴파일 단계에서 줄일 수 있다.
  • 어떤 타입을 가지는지 개발자가 알 수가 있다. 타입 추론(Type Inference)
  • 자바 코드에서 선언되고 사용된 제네릭 타입은 컴파일 시 컴파일러에 의해 자동으로 검사되어 타입 변환.


타입스크립트에서 제네릭의 모습이다.

function getText<T>(text: T): T {
  return text;
}

getText<string>('hi');
getText<number>(10);
getText<boolean>(true);


함수를 호출하는 시기에 타입을 정하는 것을 제네릭

//제네릭의 타입제한
function getText<T>(text: T): T {
  console.log(text);
  return text;
}

//함수를 호출하는 시기에 매개변수 타입을 정의
const str = getText<string>("a|b|c");
console.log(str.split("|"));

const bln = getText<boolean>(true);
//리턴타입이 boolean으로 정의 되어있기 때문에
//string의 내장 함수를 사용못함
//console.log(bln.split(""));
console.log(bln);


any 와 union type

// any
function getData(amt: any) {
  return amt.length; // 에러 발생, amt 타입이 any로 추론되기 때문에 문자열 API 사용 불가
}
 
//union type
function getAmt(amt: string | number) {
  if (typeof amt === 'string') {
    return amt.length;  // 정상 동작, amt 타입이 string으로 추론되었기 때문에 문자열 API 사용
  }
  if (typeof amt === 'number') {
    return amt.toFixed();
  }
  return new TypeError('amt Type Error!å');
}


인터페이스에서 제네릭을 이용한 예제

interface selectBox<T> {
  value: T;
  selected: boolean;
}
const strSelectBox: selectBox<string> = { value: "abc", selected: false };
const numSelectBox: selectBox<number> = { value: 123, selected: false };


클래스에서 제네릭 제약 이용한 예제

class ForeignLecture {
  name: string;
}

class English extends ForeignLecture {
  classTitle: string = "영어";
  textbook: string;
}

class Japanese extends ForeignLecture {
  classTitle: string = "일본어";
  textbook: string;
}

class Development {
  classTitle: string = "개발";
  textbook: string;
}

//함수 제약
function fnListenPlayer<T extends ForeignLecture>(lecture: T): T {
  console.log("# fnListenPlayer = " + lecture);
  return lecture;
}

//클래스 제약
class ListenPlayer<T extends ForeignLecture> {
  onPlayer(lecture: T) {
    console.log("listening to player " + lecture.name);
  }
}

let player = new ListenPlayer();
let eng = new English();
eng.name = eng.classTitle;
fnListenPlayer(eng);
player.onPlayer(eng);

let jpn = new Japanese();
jpn.name = jpn.classTitle;
fnListenPlayer(jpn);
player.onPlayer(jpn);

let dev = new Development();
//fnListenPlayer(dev); //에러, 제네릭 함수 제약
//player.onPlayer(dev); //에러, 제네릭 클래스 제약