TypeScript Generics 정리

일상 코딩·2022년 4월 10일
0

TypeScript

목록 보기
12/12
post-thumbnail

01.Generics, Any 와 다른 점

  • 제너릭 타입은 타입에 유연성을 제공하여 컴포넌트 등에서 재사용을 가능하게 해주는 타입이다.
  • 타입의 유연성이란 :string, :number 등과 같이 고정된 타입이 아닌 사용에 따라 여러 타입을 사용하게 해준다는 것이다.
  • 제너릭은 타입 정보가 동적으로 결정되는 타입이다.
  • 제너릭 타입은 다양한 타입을 받을 수 있다는 유연성이란 점에서 any 타입과 흡사하지만 타입의 정보가 동적으로 결정된다는 차이가 있다.
function helloString(message: String): String {
    return message;
}

function helloNumber(message: Number): Number {
  return message;
}

// 모든 타입으로 받거나 리턴할 수 있도록 하려면?
function hello(message: any): any {
  return message;
}

// 어떤 것도 들어올 수 있으므로 any로 인식함
console.log(hello("Mark").length);
console.log(hello(39).length); // 컴파일 타임에는 문제가 없지만 런타임에서 문제 발생

// generic
function helloGeneric<T>(message: T): T {
  return message;
}

console.log(helloGeneric("Mark").length);
console.log(helloGeneric(39));
console.log(helloGeneric(true));
  • 제너릭은 <> 기호를 이용해서 정의하며, 이름은 자유롭게 지정할 수 있다.
  • ex> function 함수이름 <제너릭이름>(인수: 제너릭 이름) : 제너릭 이름 {}

02.Generics Basic

function helloBasic<T, U>(message: T, comment: U): T {
  return message;
}

// 제네릭 타입 명시
helloBasic<String, Number>("Mark", 39); // 반환타입  String, Number

// 제네릭 타입 추론
helloBasic(36, 39); // 반환타입 36, 39

03.Generics Array & Tuple

Array

function helloArray<T>(message: T[]): T {
  return message[0];
}

helloArray(["Hello", "World"]); // 반환타입 string
helloArray(["Hello", 5]); // 반환타입 string | number

Tuple

function helloTuple<T, K>(message: [T, K]): T {
  return message[0];
} 

helloTuple(["Hello", "World"]); // 반환타입 string
helloTuple(["Hello", 5]); // 반환타입 string

04.Generics Function

type alias

type HelloFunctionGeneric1 = <T>(message: T) => T;

const helloFunction1: HelloFunctionGeneric1 = <T>(message: T): T => {
  return message;
}

interface

interface HelloFunctionGeneric2 {
  <T>(message: T): T;
}

const helloFunction2: HelloFunctionGeneric2 = <T>(message: T): T => {
  return message;
}

05.Generics Class

class Person<T, K> {  // 제네릭의 유효범위는 클래스 전체 범위 안
  private _name: T;
  private _age: K;

  constructor(name: T, age: K) {
    this._name = name;
    this._age = age;
  }
}

// 타입 추론
new Person("Mark", 39);

// 타입 명시
new Person<string, number>("Mark", 39);

06.Generics with extends

  • 제네릭 타입에 제한을 둔다.
  • 제네릭 사용시 같이 쓸 것을 권장
class PersonExtends<T extends String | Number> { // string, number만 가능
  private _name: T;

  constructor(name: T) {
    this._name = name;
  }
}

new PersonExtends("Mark");
new PersonExtends(39);
// new PersonExtends(true); // 컴파일 에러
// 제한을 통해 이 코드의 제 3자에게 올바른 가이드라인 제공

07.Keyof & type lookup system

  • 컴파일 타임에 타입을 정확히 찾아낼 수 있는 방식
  • 타입 앞에 keyof 키워드를 붙여 객체 키 이름들의 유니온 타입 반환
  • keyofObjectkey들의 lieteral 값들을 가져온다.
interface IPerson {
  name: String;
  age: Number;
}

const person: IPerson = {
  name: "Mark",
  age: 39,
};

// 지정된 객체의 키의 이름들의 유니온 타입
keyof IPerson // 'name' | 'age'

keyof 사용전: 매개변수 key 타입에 따른 리턴값 지정이 정확히 안됨

function getProp(obj: IPerson, key: 'name' | 'age'): string | number {
  return obj[key];
}

keyof 사용후: 리턴타입이 아직도 유니온 타입이다.

function getProp(obj: IPerson, key: keyof IPerson): IPerson[keyof IPerson] {
  return obj[key];
}

// IPerson[keyof IPerson]
// => IPerson["name" | age] 
// => IPerson["name"] | IPerson["age"]
// => String | Number

제네릭 적용

// 프로퍼티의 값을 가져오는 함수
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

console.log(getProp(person, 'name')); // Mark
console.log(getProp(person, 'age')); // 39

// 프로퍼티의 값을 설정하는 함수
function setProp<T, K extends keyof T>(obj: T, key: K, value: T[K]): void {
  obj[key] = value;
}

setProp(person, "name", "Anna");
setProp(person, "age", 24);

console.log(getProp(person, 'name')); // Anna
console.log(getProp(person, 'age')); // 24
profile
일취월장(日就月將) - 「날마다 달마다 성장하고 발전한다.」

0개의 댓글