그리스어로
poly
는 many, much(많은), several, multi(다수의)의 뜻을 가졌다.
morphos
혹은morphic
은 form(형태), structor(구조)의 뜻을 가졌다.
Polymorphism란 한 마디로 "여러가지의 다른 구조들"이라고 이해할 수 있다.
기본적으로 함수는 여러가지 다른 모양, 다른 형태를 가지고 있으며, overloading
처럼 다른 2~3 개의 파라미터을 가질 수 있다.
또는, Typescript에서의 함수는 string
이나 object
를 첫 번째 파라미터로 가질 수 있다.
이런 모든 것은 Polymorphism(다형성)이라고 할 수 있다.
// 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]) // 에러
함수 실행 시 number
와 boolean
타입이 아닌 경우에는 에러가 발생한다.
이 경우 call signature(concrete type
으로 전달)을 또 적어주는 것이 가장 좋은 방법일까?
타입의 placeholder 같은 것으로 concrete type
를 대신해서 사용할 수 있다.
placeholder를 이용해서 전달하는 인자를 추론하여 함수를 실행하는 것이다.
call signature를 작성할 때, 여기 들어올 확실한 타입을 모를 때 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가 유추한 타입으로 함수를 실행한다.
// 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으로 표기할 수 있다.
type SuperPrint = {
(arr: T[], x: M): T
}
const superPrint: SuperPrint = (arr, x) => arr[0]
let a = superPrint([1, "b", true], "hi");
type SuperPrint = {
(arr: any[]): any
}
const superPrint: SuperPrint = (arr) => arr[0]
let a = superPrint([1, "b", true]);
a.toUpperCase(); // pass
any를 사용하면 위와 같은 경우에도 에러가 발생하지 않는다.
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으로 "하나씩 추가하는 형태" 이기 때문이다.