본문 바로가기
Dev/TypeScript

[TypeScript] 함수 - 다형성과 제네릭

by 5kdk 2022. 12. 19.

들어가며

이번 포스팅은 타입스크립트 함수 파트를 정리한다.

polymorphism(다형성)과 generic(제레닉)의 개념을 예시 code로 살펴보자.

 

 


Polymorphism (다형성)

  • poly란? => many, serveral, much, multi
  • morphos란? => form, structure
  • polymorphos란? => poly + morphos => 여러 다른 구조

다형성이란, 여러 타입을 받아들임으로써 여러 형태를 가지는 것을 의미한다.

 

💡 Concrete type (string, number, boolean... )

 

type SuperPrint = {
	(arr: number[]): void
    (arr: boolean[]): void
    (arr: string[]): void
    (arr: (number|boolean)[]): void
}

const superPrint: SuperPrint = (arr) => {
	arr.forEach(i => console.log(i))
}

superPrint([1, 2, 3, 4])
superPrint([true, false, true, false])
superPrint(["a", "b", "c"])
superPrint([1, 2, true, false])

 

다른 타입의 인자마다 concrete type을 추가 작성해주고 있다.

물론 이 방법으로도 잘 작동한다. 하지만 어떤 타입의 인자로 들어 올지 모르는 경우?

generic을 사용하여 타입스크립트에게 더 나은 방법으로 얘기해 주어야 한다.

 

 

💡 Use Generic

type SuperPrint = {
  <TypePlaceholder>(arr: TypePlaceholder[]): TypePlaceholder;
}

const superPrint: SuperPrint = (arr) => arr[0]

const a = superPrint([1, 2, 3, 4]);
const b = superPrint([true, false, true]);
const c = superPrint(["a", "b", "c"]);
conts d = superPrint([1, 2, true, false]);

 

타입스크립트에게 generic 타입을 받을 것이라고 알려주자. <T>, <V>, <Potato> 괄호 안에는 어느 단어나 가능하다.

placeholder를 이용해서 call signature를 작성하면 타입스크립트가 발견한 타입으로 placeholder를 대체해준다.

즉, 인자들과 반환 값에 대하여 "placeholder"을 사용해서 타입에 따라 그에 상응하는 타입을 가질 수 있다.

 

 


Generic (제네릭)

 제네릭은 C#이나 Java와 같은 언어에서 재사용 가능한 컴포넌트를 만들기 위해 사용하는 기법이다.

단일 타입이 아닌 다양한 타입에서 작동할 수 있는 컴포넌트를 생성할 수 있다.

구체적인 타입을 지정하지 않고도 다양한 매개변수와 리턴 값에 대한 타입을 처리할 수 있다.

타입스크립트에서 제네릭을 통해 인터페이스, 함수 등의 재 사용성을 높일 수 있다.

 

 

💡 그렇다면 그냥 any를 넣는 것과 Generic의 차이는 무엇일까?

type SuperPrint = {
  (arr: any[]): any;
};
// type SuperPrint = (arr: any[]) => any;

const superPrint: SuperPrint = (arr) => arr[0];

let a = superPrint([1, "b", true]);

a.toUpperCase();

 

위와 같은 경우에 변수 a는 [ 1, "b", true ]의 첫 번째 인덱스를 리턴 받은 값 1이다.

a에 toUpperCase 메서드로 접근한다고 할 때 any를 사용하면 타입스크립트가 에러를 발생시키지 않는다.

 

 

type SuperPrint = {
  <T>(arr: T[]): T;
};
// type SuperPrint = <T>(a: T[]) => T;

const superPrint: SuperPrint = (arr) => arr[0];

let a = superPrint([1, "b", true]);

// error
a.toUpperCase();

 

Generic의 경우 Call Signature를 concrete type으로 하나씩 추가하는 형태이기 때문이기에, 에러가 발생해 보호받을 수 있다

 

 

type SuperPrint = {
  <T, M>(a: T[], b: M): T;
};
// type SuperPrint = <T, M>(a: T[]) => T;

const superPrint: SuperPrint = (a, b) => arr[0];

let a = superPrint([1, "b", true], "hi");

 

위와 같이 복수의 Generic을 선언해 사용할 수 있다

 

 


참고자료

https://nomadcoders.co/typescript-for-beginners

'Dev > TypeScript' 카테고리의 다른 글

[TypeScript] 함수 - Call signature와 Overloading  (0) 2022.12.18
[TypeScript] 타입스크립트 첫걸음  (0) 2022.12.11

댓글