함수의 params와 return의 타입을 정의해두고 재활용
type Add = (a:number, b:number) => number;
/*
이렇게도 표현할수 있음.
type Add = {
(a:number, b:number) : number;
}
*/
const add:Add = (a, b) => a + b;
type의 오버로딩 (여러개의 call signature가 있는 함수일뿐)
// param이 하나일때
type Config = {
path: string,
state: object,
}
type Push = {
(path:string):void
(config:Config):void
}
const push:Push = (config) => { // 여기서 config는 string일수도, object일수도
// 그러므로 아래처럼 분기해서 처리해야함.
if(typeof config === "string") {console.log(config)}
else {console.log(config)}
}
// params가 여러개일때
type Add = {
(a:number, b:number) : number
(a:number, b:number, c:number) : number // c는 옵션
}
// params의 갯수가 변경될 수 있을땐 c에 이렇게 ?를 추가해야함.
const add:Add = (a, b, c?:number) => {
if (c) return a + b + c
return a + b
}
/*
이런식으로 각 타입에 따른 call signature를 선언해서 overloading하는것은 비효율적
type SuperPrint = {
(arr: number[]):void
(arr: boolean[]):void
(arr: string[]):void
}
=> 이럴때? generic type을 써보자!!
*/
type SuperPrint = {
<T>(arr: T[]):T
// TypePlaceholder는 generic name
// generic은 param에서 발견한 타입을 알아서 정의해줌.
// 즉 여기서는 param 배열 요소의 타입 집합이 TypePlaceholder가 됨.
// 엄연히 any와는 차이가 있음
}
const superPrint: SuperPrint = (arr) => {
arr.forEach(i => console.log(i))
return arr[0]
}
superPrint([1,2,3,4])
superPrint([true, false])
superPrint(["a", "b", "c"])
// 인자가 두개 이상일떄 generic 표현
type SuperPrint = {
<T, M>(arr: T[], b:M):T
}
const superPrint: SuperPrint = (a) => a[0];
function superPrint<V>(a: V[]):V{
return a[0]
}
type Player<E> = {
name:string
extraInfo:E
}
type NicoPlayer = Player<{favFood:string}>
const nico: NicoPlayer = {
name: "nico",
extraInfo: {
favFood:"kimchi"
},
}
const lynn: Player<null> = {
name: "lynn",
extraInfo:null
}
// 두개가 같은 표현 - 타입 명시 vs generic에 타입 넣기
function print(arr: number[]){}
function print(arr: Array<number>){}