Jin's Study

[Typescript] polymorphism(다형성), generic 본문

Front-end/TypeScript

[Typescript] polymorphism(다형성), generic

PolarJin 2024. 8. 6. 13:45

🔎 Polymorphism :

여러가지 다양한 형태
객체 지향 프로그래밍(OOP)의 개념 중 하나.
다양한 형태의 객체를 다룰 수 있는 능력을 의미
다양한 타입의 객체들이 공통의 인터페이스를 통해 동일한 방식으로 처리될 수 있다.
-> 코드의 유연성재사용성을 높일 수 있음.
tyoe 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])
superPrint(["a", "b", "c"])
superPrint([1, 2, true, false])
type SuperPrint = {
	<TypePlaceholder>(arr: TypePlaceholder[]): TypePlaceholder
}

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

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

 

🔎 Generic:

타입의 placeholder같은 개념.
코드의 재사용성을 높이고 타입의 안정성을 제공
다양한 타입을 처리할 수 있으며, 컴파일 타임에서 타입 검사를 통해 오류를 방지

call signature을 사용하면서 concrete type을 알 수 없을 때, 그때 generic을 사용한다. 
"타입을 매개변수로 받는" 타입. 타입을 미리 지정하지 않고, 호출 시점에 타입을 결정할 수 있다.

 

tyoe SuperPrint = {
	<TypePlaceholder>(arr: TypePlaceholder[]):void
    
}

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

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

 

  • 아무거나 넣어도 알아서 타입을 분석해서 나오는 거라면, call signature에 any를 써도 된다고 생각이 들 수도 있다.
    하.지.만. any의 경우 타입 오류가 나야하는 상황에서도 오류가 나지 않는 문제가 발생할 수 있다. 즉, 타입의 안정성을 제공하지 않는다.
any와 제네릭의 차이점

타입 안전성:
- any: 타입 안전성을 제공하지 않음. 타입 검사가 수행되지 않으며, 런타임 오류가 발생할 가능성이 높음.
- 제네릭: 타입 안전성을 제공함. 제네릭 매개변수를 사용하여 타입을 정의하고, 컴파일 타임에 타입 검사를 통해 오류를 사전에 방지함.

타입 유연성:
- any: 타입을 전혀 제한하지 않음. 어떤 값이든 저장할 수 있지만, 이로 인해 코드의 신뢰성이 떨어짐.
- 제네릭: 특정 타입의 값을 받아들일 수 있도록 설계되어 있으며, 타입 매개변수를 통해 타입 유연성을 제공하지만, 타입 검사를 통해 신뢰성을 유지함.

컴파일 타임 검증:
- any: 컴파일 타임에 타입 검증이 없으므로, 런타임 오류의 원인이 될 수 있음.
- 제네릭: 컴파일 타임에 타입 검증이 이루어지므로, 타입 오류를 사전에 확인하고 방지할 수 있음.

그렇기때문에 generic을 통해 내가 요구한 대로 signature를 사용하게 해줘서 오류가 발생해도 확인 가능할 수 있도록 잡아주어야한다.

 

  • generic을 처음 인식했을 때와 genecric의 순서를 기반으로 generic의 타입을 알게 된다.
type SuperPrint = {
	<T,M>(arr: T[], b: M): T
}

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

cosnt a = superPrint([1, 2, 3, 4], "X")
const b = superPrint([true, false, true], 1)
const c = superPrint(["a", "b", "c"], false)
const d = superPrint([1, 2, true, false, "hello"], [])