티스토리 뷰

다형성(Polymorphism)

❓poly란?

  • many, serveral, much, multi 등과 같은 뜻

❓morphos란?

  • form, structure 등과 같은 뜻

❗polymorphos = poly + morphos = 여러 다른 구조

 

1. concrete type ?

  • number, boolean, void 등 지금까지 배운 타입
  • unknown, void, number,boolean,string 등

2. generic (제네릭) :

  • 제네릭은 타입의 placeholder같은 것이다.
💡 <T>(arr: T[]):T

 

//concrete type을 사용한 콜 시그니처
(arr: number[]):void
(arr: boolean[]):void
(arr: string[]):void
(arr: (number|boolean)[]):void

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

const a = myPrint([1,2,3,4])
const d = myPrint([1,2,true,false,"hi"]) // 에러!

👉  const d가 어떤 타입이 오든 작동하게 하고 싶다면? generic 사용하기

 

 

제네릭을 사용하는 이유는?

콜 시그니처에 들어올 확실한 타입을 모를 때 제네릭을 사용한다.

(arr: number[])이 아규먼트가 제네릭을 받는다고 TS에게 알려준다. 즉, 이 콜 시그니처가 제네릭을 받는다고 알려주는 방법이다.

type SuperPrint = {
    //콜 시그니처 작성 
   //SuperPrint 함수는 많은 형태를 가지고 있게 됨.(number, string+boolean 등 여러 타입)
    <TypePlaceholder>(arr: TypePlaceholder[]):TypePlaceholder  
}
//배열의 첫 번째 요소를 리턴하게 만들기
const myPrint: SuperPrint = (arr) => arr[0]

//placeholser를 이용해서 콜 시그니처를 작성하면 여기에서 TS는 placeholder대신 TS가 발견한 타입으로 바꿔줌
const a = myPrint([1,2,3,4])  // <number>(arr: number[]) => void
const b = myPrint([true,false,true]) //b : boolean
const c = myPrint(["a","b","c"]) // c: string
const d = myPrint([1,2,true,false,"hi"]) //어떤 타입이 오든 작동하게 하고 싶다면? generic사용하기

placeholder를 이용해서 콜 시그니처를 작성하면,

여기에서 TS는 placeholder 대신 TS가 발견한 타입으로 바꿔준다.

 

 

Generics 제네릭

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

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

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

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

 

 

any와 generic type의 차이점?

any를 쓰면 TS의 보호장치에서 벗어나기 때문에 에러를 잡아내기 힘들다.

제너릭을 써서 코드에 따른 타입을 보장해주는 것이 좋다.

type SuperPrint = (a: any[]) => any

const myPrint: SuperPrint = (a) => a[0] 

const d = myPrint([1,2,true,false,"hi"])
d.toUpperCase(); // error!
type SuperPrint = <T>(a: T[]) => T

 

제네릭은 내가 요구한 대로 signature(콜시그니처)를 생성해줄 수 있는 도구라고 생각하면 된다.

 

type SuperPrint = <T,M>(a: T[], b:M) => T

const myPrint: SuperPrint = (a) => a[0] 

const a = myPrint([1,2,3,4], "x") 
const b = myPrint([true,false,true], 1)
const c = myPrint(["a","b","c"], false) 
const d = myPrint([1,2,true,false,"hi"], [])

 

⇒ 여기까지의 예시는 콜 시그니처를 직접 생성해주고 있음.

 

제네릭 개념을 한마디로 설명하면,

제네릭은 선언 시점이 아니라 생성 시점에 타입을 명시하여 하나의 타입만이 아닌 다양한 타입을 사용할 수 있도록 하는 기법이다.

 

Conclusions

콜 시그니처 이외에 사용법을 알아보자.

function nicePrint<T>(a: T[]){
    return a[0]
}

//boolean 타입이라고 명시해 주고 있음.
const aa = nicePrint<boolean>([1,2,3,4], "x") 
//에러! TS에 overwrite(덮어쓰기)했기 때문에 에러가 남.

//항상 타입스크립트가 타입을 유추할 수 있게 하는게 좋음! 스스로 타입을 찾게 하자
const aa = nicePrint([1,2,3,4])
const bb = nicePrint([true,false,true])
const cc = nicePrint(["a","b","c"]) 
const dd = nicePrint([1,2,true,false,"hi"])

 

항상 타입스크립트가 타입을 유추할 수 있게 하는게 좋음! 스스로 타입을 찾게 하자

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/09   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함