들어가며
이번 포스팅은 타입스크립트 함수 파트를 정리한다.
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을 선언해 사용할 수 있다
참고자료
'Dev > TypeScript' 카테고리의 다른 글
[TypeScript] 함수 - Call signature와 Overloading (0) | 2022.12.18 |
---|---|
[TypeScript] 타입스크립트 첫걸음 (0) | 2022.12.11 |
댓글