[TIL] Typescript - functions(Call Signatures, Overloading, Generics)

👉🏼 KIM·2024년 10월 15일

TIL

목록 보기
22/54

오늘 공부한것 & 기억하고 싶은 내용

Call Signatures

  • 함수가 어떻게 호출되는지 설명해준다.
  • 객체가 함수처럼 호출될 때 사용할 매개변수(parameter)반환 타입(return type)을 정의한다.
  • 이것은 객체의 프로퍼티로서 함수를 정의하는 것과 비슷한 역할을 한다.
type Favorite = {
pizza: string;
(args: number): boolean;//Call Signature
};

//일반 함수
function hello(FF: Favorite) {
  console.log(FF.pizza, FF(6));
}

//화살표 함수
const hello = (FF: Favorite) => {
  console.log(FF.pizza, FF(6));
};
}


const myFavorite: Favorite = (num: number) => num > 5;
myFavorite.pizza = "Margherita";

console.log(myFavorite.pizza);  // 출력: Margherita
console.log(myFavorite(6));     // 출력: true (6 > 5 이므로)

Overloading

  • 함수가 여러개의 call Signatures를 가지고 있을때 발생시킨다.
  • 실제로 내가 코드를 짤때는 오버로딩된 함수를 만드는것은 드물다. 하지만 패키지나 라이브러리에서 많이 사용하기 때문에 알아둬야한다.
type Add = {
(a:number ,b :number) : number
(a:number, b :string) : number
}
const add: Add = (a,b) =>{
if(typeof b === "string") return a
return a + b
}

//ex next js 에서의 오바로딩
//push의 다양한 기능
Route.push({
path: "/home",
state: 1
})

Router.push("/home")

//제대로 된 오버로딩의 예시
type Config = {
path: string,
state: number
}

type Push = {
(config: Config): void,
(config: string): void
}

const push: Push = (config) => {
if (typeof config === "string") console.log(config);
else console.log(config.path);
}

//파라미터의 갯수가 달라도 된다
type Add ={
(a:number,b:number):number;
(a:number,b:number,c:number):number;
}
//a , b만 return 하고 싶을 때 c까지 확인하고 싶을 때 다양하게 사용하면 된다.
const add:Add=(a,b,c?:number)=>{
if(c) return a+b+c;
return a+b;
}

add(1,2)
add(1,2,3)

Polymorphism(다형성, 폴리모피즘)

  • 다형성이란, 여러 타입을 받아들임으로써 여러 형태를 가지는 것을 의미함
  • poly란? many, serveral, much, multi 등과 같은 뜻
  • morphos란? form, structure 등과 같은 뜻
  • polymorphos = poly + morphos = 여러 다른 구조
  • concrete type: number, boolean, void 등 지금까지 배운 타입
  • generic type: 타입의 placeholder
type SuperPrint = { (arr: T[]): void }
type SuperReturn = { (arr: T[]): T }

const superPrint: SuperPrint = (arr) => {
    arr.forEach(i => console.log(i))
}
const superReturn: SuperReturn = (arr) => arr[0]

superPrint([1, 2, false, true])
console.log(superReturn([1, 2, 3, 4]))

Generics

  • 변수나 인수에 타입을 정해주는 Concrete같이 딱딱한 기법과 달리 어떤 타입을 쓸지 정해주지 않고 그 타입에 대해 어떤 변수를 넣어주냐에 따라 결정되는 유연한 기법
  • 사용자가 요청하는 방식에 맞춰 Call Signature(함수의 매개변수와 반환 타입을 명시한 서명)를 만들어주는 도구 역할. 즉, 같은 함수라도 다양한 타입에 대해 작동할 수 있게 해준다.
  • 선언 시점이 아니라 사용(생성) 시점에 타입을 명시하여, 하나의 타입에 고정되지 않고 다양한 타입에 대해 유연하게 동작할 수 있도록 하는 기법

Any와 Generic의 차이

any는 말 그대로 모든 타입을 받을 수 있다. 하지만, 타입 정보를 잃어버리기 때문에, 함수가 반환할 때도 그 타입 안전성이 보장되지 않는다. 즉, 어떤 타입을 받아도 함수는 항상 any 타입을 반환하므로, TypeScript가 타입 체크를 해주지 않는다.

function identity(value: any): any {
  return value;
}

const result = identity(10);  // result는 any, 타입이 보장되지 않음

반면 generics은 어떤 타입이든 받을 수 있다는 점에서 any와 같지만 해당 정보를 잃지 않고, 그 요구에 맞는 시그니처를 생성해줄 수 있는 도구이다. 즉, 어떤 타입을 받았는지 알고, 그에 맞는 타입을 반환해준다.

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

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

let a = superPrint([1, "b", true]);
// pass
a.toUpperCase();

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

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

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

let a = superPrint([1, "b", true]);
// error
a.toUpperCase();

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

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

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

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

배운점 & 느낀점

  • 배운점 & 느낀점
  • 길게 작성하고싶다면 포스팅 후에 링크
profile
프론트는 순항중 ¿¿

0개의 댓글