제네릭

function func<T>(value: T): T {
  return value;
}

let num = func(10);

제네릭(Generic) : 일반적인, 포괄적인

제네릭 함수로 만들어, 인수에 따라서 반환 값의 타입을 가변적으로 정할 수 있음.

<T>은 타입 변수

함수를 호출할 때마다 결정됨.

타입변수를 명시적으로 직접 정의

function func<T>(value: T): T {
  return value;
}

let arr = func<[number, number, number]>([1, 2, 3]);

타입 변수 응용하기

function swap<T, U>(a: T, b: U) {
  return [b, a];
}

const [a, b] = swap("1", 2);

타입변수는 여러개를 사용할 수 있다.

function returnFirstValue<T>(data: T) {
  // T로만 했을때에는 return에 타입에러가 발생한다.
  // 왜냐하면 타입변수가 어떤것이 들어올지 모르기때문에 "unknown"으로 추론되기 때문이다.
  return data[0];
}

function returnFirstValue<T>(data: T[]) {
  // 이를 해결하기 위한 방법으로는 들어오는 데이터를 배열형태로 바꿔주면 된다.
  // 이렇게 하면 return되는 배열의 인덱스를 "unknown[]"로 추론할 수 있기 때문이다.
  return data[0];
}

function returnFirstValue<T>(data: T, ...unknown[]) {
  // 튜플타입으로 해도 타입 추론이 잘 된다.
  // 첫번쨰값만 리턴할것이기 때문에 2번째 인자부터는 알 필요가 없음.
  return data[0];
}

let num = returnFirstValue([0, 1, 2]); // return number

let str = returnFirstValue(["hello", "mynameis"]); // return string

let str = returnFirstValue([1, "hello", "mynameis"]); // return number | string
function getLength<T extends { length: number }>(data: T[]) {
  return data.length;
}

let var1 = genLength([1, 2, 3]); // 3
let var2 = getLength("12345"); // 5
let var3 = getlength({ length: 10 }); // 10

let var4 = getLength(10); // number형식의 인수는 {length : number} 형식에 할당될 수 없음.

map, forEach 메서드 타입 정의

// map

const arr = [1, 2, 3];
const newArr = arr.map((it) => it * 2); // [2, 4, 6]

// map<U>(callbackFn : (value : T, index : number, array : T[]) => U, thisArg?: any) : U[];

function map<T, U>(arr: T[], callback: (item: T) => U): U[] {
  let result = [];
  for (let i = 0; i < arr.length; i++) {
    result.push(callback(arr[i]));
  }
  return result;
}

map(arr, (it) => it.toString());
// forEach

function forEach<T>(arr: T[], callback: (item: T) => void) {
  for (let i = 0; i < arr.length; i++) {
    callback(arr[i]);
  }
}

forEach(arr2, (it) => {
  console.log(it.toFixed);
});

제네릭 인터페이스와 제네릭 타입 별칭

제네릭 인터페이스

타입 변수 = 타입 파라미터 = 제네릭 타입 변수 = 제네릭 타입 파라미터

interface KeyPair<K, V> {
  key: K;
  value: V;
}

let keyPair: KeyPair<string, number> = {
  key: "key",
  value: 0,
};

let keyPair2: KeyPair<boolean, string[]> = {
  key: true,
  value: ["1"],
};

인덱스 시그니처(Index Signature)

interface NumberMap {
  [key: string]: number;
}

let numberMap1: NumberMap = {
  key: -1231,
  key2: 123123,
};

interface Map<V> {
  [key: string]: V;
}

let stringMap: Map<string> = {
  key: "value",
};

let booleanMap: Map<boolean> = {
  key: true,
};

제네릭 타입 별칭

type Map2<B> = {
  [key: string]: V;
};

let stringMap2: Map2<string> = {
  key: "hello",
};

제네릭 인터페이스의 활용 예시

유저 관리 프로그램 유저 구분 : 학생 유저 / 개발자 유저

interface Student {
  type: "student";
  school: string;
}

interface Developer {
  type: "developer";
  skill: string;
}

interface User<T> {
  name: string;
  profile: T;
}

function goToSchool(user: User<Student>) {
  const school = user.profile.school;
  console.log(`${school}로 등교 완료`);
}

const developerUser: User<Developer> = {
  name: "이정환",
  profile: {
    type: "developer",
    skill: "TypeScript",
  },
};

const studentUser: User<Student> = {
  name: "홍길동",
  profile: {
    type: "student",
    school: "가톨릭대학교",
  },
};

제네릭 클래스

class List<T> {
  constructor(private list: T[]) {}

  push(data: T) {
    this.list.push(data);
  }

  pop() {
    return this.list.pop();
  }

  print() {
    console.log(this.list);
  }
}

const numberList = new List<number>([1, 2, 3]);
const stringList = new List<string>(["1", "2"]);

프로미스와 제네릭

const promise = new Promise<number>((resolve, reject) => {
  setTimeout(() => {
    // 결과값 : 20
    resolve(20);
  }, 3000);
});

promise.then((response) => {
  // response는 number 타입
  console.log(response);
});

promise.catch((error) => {
  if (typeof error === "string") {
    console.log(error);
  }
});
function fetchPost() {
  return new Promise<Post>((resolve, reject) => {
    setTimeout(() => {
      resolve({
        id: 1,
        title: "게시글 제목",
        content: "게시글 본문",
      });
    }, 3000);
  });
}

function fetchPost(): Promise<Post> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        id: 1,
        title: "게시글 제목",
        content: "게시글 본문",
      });
    }, 3000);
  });
}

Last updated