참고자료: 공식문서 가이드(함수 part)
Call Signatures
- 함수를 어떻게 호출해야 하는지 + 인자(arguments)의 타입과 함수의 반환 타입에 대해 알려줌
- 함수의 매개 변수(parameter)와 반환 타입을 지정
- 나만의 call signature 선언하기
→ ex) 변수 add 선언시 매번 (a:number, b:number)을 작성하지 않아도 add:Add 만으로 대체 가능
// ex.1
type Add = (a:number, n:number) => number;
const add:Add = (a, b) => a + b
// ex.2
type PizzaFunction = {
pizza: string;
(args: number): boolean;
};
function hello(fn: PizzaFunction) {
console.log(fn.pizza, fn(6));
}
Function Overloading (Method Overloading)
- 동일한 이름에 매개 변수와 매개 변수 타입 또는 리턴 타입이 다른 여러 버전의 함수를 만드는 것
- 외부 패키지 or 라이브러리에서 자주 보이는 형태
- 하나의 함수가 서로 다른 여러 개의 call Signature를 가지고 있을 때 발생
- 이론적인 예시:
예시 1) 매개변수의 데이터 타입이 다른 경우
// 에러 발생 (b: string | number 이기 때문)
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;
}
예시 2) 매개변수의 수가 다른 경우 (여러 개의 argument를 가질 때)
// 에러 발생
type Add2 = {
(a: number, b: number): number,
(a: number, b: number, c: number): number
}
// 예외 처리
const add2: Add2 = (a, b, c?: number) => {
if (c) return a + b + c;
return a + b;
}
- 실제 예시:
Next.js의 라우터에서 페이지를 이동하는 상황
router.push("/home");
router.push({
path: "/home",
state: 1
});
// 아래와 같은 두 가지 경우의 Overloading으로 디자인됨
type Config = {
path: string,
state: number
}
type Push = {
(config: Config): void, // void는 return하지 않는다는 의미
(config: string): void
}
const push: Push = (config) => {
if (typeof config === "string") console.log(config);
else console.log(config.path, config.state);
}
Polymorphism (다형성)
- poly(여러 가지의) + morpho(구조) = 여러 다른 구조
→ 여러 타입을 받아들임으로써 여러 형태를 가지는 것 - concrete type: number, boolean, void 등 지금까지 배운 타입
- generic type: 타입의 placeholder
- 다양한 경우를 커버하는 함수를 작성할 때,
모든 조합의 Call Signature를 concrete type으로 적어주는 일은 번거로움
→ type에 Generic을 할당하면 호출된 값으로 concrete type을 가지는 Call Signature를 역으로 보여주는 다형성(Polymorphism)을 가짐
type SuperPrint = { (arr: T[]): void }
type SuperReturn = { (arr: T[]): T } // 다른 이름이어도 상관 없으나 주로 T라고 씀
const superPrint: SuperPrint = (arr) => {
arr.forEach(i => console.log(i))
}
const superReturn: SuperReturn = (arr) => arr[0]
superPrint([1, 2, false, true]) // 자동으로 number | boolean type 감지
console.log(superReturn([1, 2, 3, 4]))
Generics
- 다양한 타입에서 작동할 수 있는 컴포넌트를 생성
- 구체적인 타입을 지정하지 않고 다양한 인수와 리턴 값에 대한 타입을 처리
- 제네릭을 통해 인터페이스, 함수 등의 재사용성을 높일 수 있음
- any와 Generic의 차이: any는 TS의 타입 체커로부터 보호를 받지 못함
// any를 사용할 경우 에러 발생 X (타입 체크 안됨)
type SuperPrint = {
(arr: any[]): any
}
const superPrint: SuperPrint = (arr) => arr[0]
let a = superPrint([1, "b", true]);
a.toUpperCase();
// generic을 선언한 경우: 에러 발생 O (타입 체크중)
type SuperPrint = {
(arr: T[]): T
}
const superPrint: SuperPrint = (arr) => arr[0]
let a = superPrint([1, "b", true]);
a.toUpperCase();
// 여러 개의 generic도 선언 가능하다
type SuperPrint = {
(arr: T[], x: M): T
}
const superPrint: SuperPrint = (arr, x) => arr[0]
let a = superPrint([1, "b", true], "hi");
- generic의 실제 사용 예시
type Player = {
name: string,
extraInfo: T
};
type MePlayer = Player;
type MeExtra = {age: number};
const player: MePlayer = {
name: "jia",
extraInfo: {
age: 25
}
};
const player2: Player = {
name: "nino",
extraInfo: null
};
'Web > TypeScript' 카테고리의 다른 글
[TypeScript] 🐥 타입스크립트를 왜 써야 할까? + 기본 Type System (0) | 2023.05.15 |
---|