Notice
Recent Posts
Recent Comments
Link
관리 메뉴

윤일무이

[TypeScript] 제네릭 인터페이스 본문

❔ TypeScript/💭 한 입 크기 TypeScript

[TypeScript] 제네릭 인터페이스

썸머몽 2023. 12. 21. 22:01
728x90

제네릭 인터페이스

  • 제네릭은 인터페이스에도 적용할 수 있다.
  • 인터페이스에 타입 변수를 선언해 사용하면 된다.
interface KeyPair<K, V> {
  key: K;
  value: V;
}

let keyPair: KeyPair<string, number> = {
  key: 'key',
  value: 1,
};

let keyPair2: KeyPair<boolean, string[]> = {
  key: true,
  value: ['1'],
};
  • 키페어를 저장하는 객체 타입을 제네릭 인터페이스로 정의했다.
  • 변수 keyPair에서는 타입으로 KeyPair<string, number>를, keyPair2에서는 KeyPari<boolean, string[]>을 정의했다.
  • 그러면 key에는 K = string | boolean, V = number | string[]으로 정의되게 된다.
  • 제네릭 인터페이스는 제네릭 함수와 달리 변수의 타입으로 정의할 때, 반드시 꺽쇠와 함께 타입 변수에 할당할 타입을 명시해야 한다.

with 인덱스 시그니처

// 인덱스 시그니처
type countryCodes = {
  [key: string]: string;
};

let countryCodes: countryCodes = {
  korea: 'ko',
  usa: 'us',
  uk: 'uk',
};
  • 인덱스 시그니처는 키와 밸류의 규칙을 기준으로 객체의 타입을 정할 수 있는 문법을 말한다.
  • 제네릭 인터페이스를 인덱스 시그니처와 함께 사용하면 훨씬 유연한 객체 타입을 정의할 수 있다.
interface Map<V> {
  [key: string]: V;
}

let stringMap: Map<string> = {
  key: 'hi',
};

let booleanMap: Map<boolean> = {
  key: true,
};
  • 한 개의 타입 변수 V를 갖는 제네릭 인터페이스 Map을 정의했다.
  • 이 V로 string 타입을 정의하는 변수 stringMap, boolean 타입을 정의하는 변수 booleanMap을 만들었다.
  • key는 string 타입이면 되고, value는 V 타입이면 되는데, 이 V타입을 각각 꺽쇠 안에 넣어준 것

제네릭 타입 별칭

// 타입 별칭
type User = {
  id: number;
  name: string;
  nickname: string;
  birth: string;
  bio: string;
  location: string;
};

let user: User = {
  id: 1,
  name: '썸머몽',
  nickname: 'summermong',
  birth: '1997',
  bio: 'hi',
  location: 'suwon',
};
  • 타입 별칭은 타입을 변수처럼 지정한 것을 말한다.
  • 이 타입 별칭도 제네릭을 적용할 수 있다.
type Map2<V> = {
  [key: string]: V;
};

let map2: Map2<string> = {
  key: '1',
};
  • 제네릭 인터페이스와 동일하게 타입 정의 시 반드시 타입 변수에 설정할 타입을 명시해줘야 한다.

제네릭 인터페이스 활용

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

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

interface User {
  name: string;
  profile: Student | Developer;
}

function goToSchool(user: User<Student>) {
  if (user.profile.type !== "student") {
    console.log("잘 못 오셨습니다");
    return;
  }

  const school = user.profile.school;
  console.log(`${school}로 등교 완료`);
}

const developerUser: User = {
  name: "summermong",
  profile: {
    type: "developer",
    skill: "typescript",
  },
};

const studentUser: User = {
  name: "wintermong",
  profile: {
    type: "student",
    school: "인하대학교",
  },
};
  • Student, Developer 타입을 정의했다. 두 타입은 모두 string literal 타입의 type 프로퍼티를 갖고 있는 서로소 유니언 타입이다.
  • User 타입은 학생일 수도 있고 개발자일 수도 있다.
  • 학생 유저만 사용할 수 있는 goToSchool이라는 함수가 있다. User 타입의 객체를 받아 유저가 학생일 때만 콘솔에 뭔가를 찍는다.
  • 그러나 특정 속성만 할 수 있는 기능이 많아지면 타입을 좁히는 코드가 많아지므로 중복 코드가 생기고 번거로워진다.
  • 이 때 제네릭 인터페이스를 사용하면 좋다.
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: "summermong",
  profile: {
    type: "developer",
    skill: "TypeScript",
  },
};

const studentUser: User<Student> = {
  name: "wintermong",
  profile: {
    type: "student",
    school: "인하대학교",
  },
};
  • User 타입의 타입 변수 T를 정의하면 profile에 따라 T가 정의된다.
  • 예를 들어 Student로 들어오면 profile에 T (Student)가 들어오게 되는 것이다.
  • 그래서 goToSchool은 User 타입에서도 Student만 이 함수의 인수로 전달할 수 있게 한다.

 


**출처: 한 입 크기로 잘라먹는 타입스크립트 (인프런, 이정환 강사님)

728x90