Typescript | Polymorphism(다형성)

이동주·2022년 6월 29일
0

Typescript

목록 보기
4/7
post-thumbnail

Polymorphism(다형성)

1. 다형성이란?

1) Polymorphism의 어원

그리스어로 poly는 many, much(많은), several, multi(다수의)의 뜻을 가졌다.
morphos 혹은 morphic은 form(형태), structor(구조)의 뜻을 가졌다.
Polymorphism란 한 마디로 "여러가지의 다른 구조들"이라고 이해할 수 있다.

2) Typescript에서의 Polymorphism

기본적으로 함수는 여러가지 다른 모양, 다른 형태를 가지고 있으며, overloading처럼 다른 2~3 개의 파라미터을 가질 수 있다.
또는, Typescript에서의 함수는 string이나 object를 첫 번째 파라미터로 가질 수 있다.

이런 모든 것은 Polymorphism(다형성)이라고 할 수 있다.

2. generic type

1) 배열을 출력하는 함수 만들기

// call signature
type SuperPrint = {
	(arr: number[]): void
    (arr: boolean[]): void
}

// 함수 구현
const superPrint: SuperPrint = (arr) => {
	arr.forEach((item) => console.log(item))
}

// 함수 실행
superPrint([1, 2, 3, 4])
superPrint([true, true, false, false])
superPrint(["1", "2", "3", "4"]) // 에러
superPrint([1, true, "2", 4]) // 에러

함수 실행 시 numberboolean 타입이 아닌 경우에는 에러가 발생한다.
이 경우 call signature(concrete type 으로 전달)을 또 적어주는 것이 가장 좋은 방법일까?

2) generic type 개념

타입의 placeholder 같은 것으로 concrete type 를 대신해서 사용할 수 있다.
placeholder를 이용해서 전달하는 인자를 추론하여 함수를 실행하는 것이다.

+ generic type을 왜 사용할까?

call signature를 작성할 때, 여기 들어올 확실한 타입을 모를 때 generic type을 사용한다.

3) generic type 사용방법

// call signature
type SuperPrint = {
	<TypePlaceHolder>(arr: TypePlaceHolder[]): void
}

// 함수 구현
const superPrint: SuperPrint = (arr) => {
	arr.forEach((item) => console.log(item))
}

// 함수 실행
superPrint([1, 2, 3, 4])
superPrint([true, true, false, false])
superPrint(["1", "2", "3", "4"]) 
superPrint([1, true, "2", 4])

call signature<TypePlaceHolder>(arr: TypePlaceHolder[]): void 로 바꾸면 generic type을 사 용하게 되어 Typescript가 유추한 타입으로 함수를 실행한다.

+ return 하는 generic type

// call signature
type SuperPrint = {
	<TypePlaceHolder>(arr: TypePlaceHolder[]): TypePlaceHolder
}

// 함수 구현
const superPrint: SuperPrint = (arr) => arr[0]

// 함수 실행
const a = superPrint([1, 2, 3, 4])
const b = superPrint([true, true, false, false])
const c = superPrint(["1", "2", "3", "4"]) 
const d = superPrint([1, true, "2", 4])

return 하는 값에서도 generic type으로 표기할 수 있다.

+ 복수의 generic type

type SuperPrint = {
	(arr: T[], x: M): T
}

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

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

3. any vs generic type

1) any

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

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

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

a.toUpperCase(); // pass

any를 사용하면 위와 같은 경우에도 에러가 발생하지 않는다.

2) generic type

type SuperPrint = {
	(arr: T[]): T
}

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

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

a.toUpperCase(); // error

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

profile
안녕하세요 이동주입니다

0개의 댓글