Generics, Any 차이점

function helloString(message: string): string {
  return message;
}

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

// 반복된 함수들 생성..

function hello(message: any): any {
  return message;
}

console.log(hello("Anna").length);
console.log(hello(20).length); // 숫자는 length 를 받을 수 없음
function helloGeneric<T>(message: T): T {
  return message;
}

console.log(helloGeneric("Jennie"));
// function helloGeneric<"Jennie">(message: "Jennie"): "Jennie"
// 리터럴 타입으로 추론

console.log(helloGeneric("Jennie").length);
// (property) String.length: number

console.log(helloGeneric(20));
// function helloGeneric<20>(message: 20): 20

console.log(helloGeneric(20).length);
// Error! 
// '20' 형식에 'length' 속성이 없습니다.ts(2339)

console.log(helloGeneric(true));
// function helloGeneric<true>(message: true): true

Generics Basic

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

helloBasic<string>(20);
// Error!
// 'number' 형식의 인수는 'string' 형식의 매개 변수에 할당될 수 없습니다.ts(2345)

helloBasic<string>("Hello");

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

helloBasic<string, number>("Hello", 20);

helloBasic(33, 40);
// function helloBasic<33, number>(message: 33, comment: number): 33

Generics Array & Tuple

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

helloArray(["Hello", "World"]);
// function hellloArray<string>(message: string[]): string

helloArray(["Hello", 7]);
// function hellloArray<string | number>(message: (string | number)[]): string | number

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

helloTuple(["Hello", "World"]);
// function helloTuple<string, string>(message: [string, string]): string

helloTuple(["Hello", 7]);
// function helloTuple<string, number>(message: [string, number]): string

Generics Function

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

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

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

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

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>(30); 
// Error! 'number' 형식의 인수는 'string' 형식의 매개 변수에 할당될 수 없습니다.ts(2345)
new Person<string, number>("Mark", "age");
// Error! 'string' 형식의 인수는 'number' 형식의 매개 변수에 할당될 수 없습니다.ts(2345)

Generics with extends

class PersonExtends<T extends string | number> {
  private _name: T;

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

new PersonExtends('Mark');
new PersonExtends(30);
// new PersonExtends(true);
// Error! 'boolean' 형식의 인수는 'string | number' 형식의 매개 변수에 할당될 수 없습니다.ts(2345)

keyof & type lookup system

interface IPerson {
  name: string;
  age: number;
}

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

// IPerson[keyof IPerson] 
// => IPerson["name" | "age"] 
// => IPerson["name"] | IPerosn["age"] 
// => string | number
// function getProp(obj: IPerson, key: keyof IPerson): IPerson[keyof IPerson] {
//   return obj[key];
// }

// function getProp<T>(obj: T, key: keyof T): T[keyof T] {
//   return obj[key];
// }

function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

getProp(person, 'name');
// function getProp<IPerson, "name">(obj: IPerson, key: "name"): string
getProp(person, 'age');
// function getProp<IPerson, "age">(obj: IPerson, key: "age"): number

// function setProp(obj: IPerson, key: keyof IPerson, value: string | number): void {
//   obj[key] = value;
// }
// Error! 
// 'string | number' 형식은 'never' 형식에 할당할 수 없습니다.
// 'string' 형식은 'never' 형식에 할당할 수 없습니다.ts(2322)

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", 20);
profile
성장하는 개발자 유슬이 입니다!

0개의 댓글