// Generic
// 함수 version

interface Obj {
    x: number
}

type Arr = [number, number]

// 이렇게 overloading 하면 경우의 수를 다 따져줘야 한다.
// function toArray(a:string, b:string): string[]
// function toArray(a:number, b:number): number[]
// function toArray(a:boolean, b:boolean): boolean[]
// function toArray(a:Obj, b:Obj): Obj[]
// function toArray(a:Arr, b:Arr): Arr[]
// function toArray(a:number, b:number) {
//     return[a,b]
// }

// T는 data type을 가지고 있다
// 이거를 제네릭이라고 한다.
function toArray <T>(a:T, b:T) {
    return[a,b]
}

// 함수를 호출할 때도, 꺽쇠를 사용하여, T의 타입을 지정할 수 있음.
console.log(toArray<string>('Neo',123)) // 다른 타입일 경우 에러 발생
// 제네릭(Generic)
// class

// 클래스 맨 앞에 어떠한 타입이 제네릭을 사용하여 넣을 수 있다.
class User<P> {
    constructor(public payload: P ) {
    }
    getPayload() {
        return this.payload
    }
}

interface UserAType {
    name: string
    age: number
    isValid: boolean
}

interface UserBType {
    name: string
    age: number
    emails: string[]
}

const Heropy = new User<UserAType> ({
    name: 'Heropy',
    age: 85,
    isValid: true,
})

const neo = new User<UserBType> ({
    name: 'Neo',
    age: 102,
    emails: ['[email protected]']
})

console.log(neo.getPayload())

Untitled

// Generic
// 인터페이스, 제약 조건(Constraints)
// 제약조건을 걸어보자. (허용하는 타입만 받아보기)

// <T extends string|number> <- String과 number만 받을 수 있다.
interface MyData<T> {
    name: string
    value: T
}

const dataA: MyData<string> = {
    name: 'Data A',
    value: 'Hello world'
}

const dataB : MyData<number> = {
    name : 'Data B',
    value: 1234
}

const dataC : MyData<boolean> = {
    name: 'Data C',
    value: false
}

const dataD : MyData<number[]> = {
    name: 'Data D',
    value: [1,2,3,4]
}

참조