본문 바로가기

JavaScript/TypeScript

타입스크립트 제네릭 (+상한 제한)

반응형
//제네릭
//:클래스나 함수, 인터페이스를 다양한 타입으로 재사용 가능
// -> 실제로 사용할때 타입을 선택할 수 있다.
//즉, 특정한 타입을 고정하지 않고 나중에 실제로 사용될 타입을 동적으로 지정

//function getSize(arr):number{
//에러 발생 : 타입을 명시하지 않았기 때문에
// function getSize(arr:number[]):number{
//-> 숫자배열이라고 타입 명시 -> 문자열로도 이 메서드를 쓰고 싶은데?
//(1) 함수 오버로드 
// 함수 오버로드 정의
function getSize(arr: string[]): number;
function getSize(arr: number[]): number;
function getSize(arr:number[] |string[]):number{
    return arr.length;
}

// 사용 예시
const stringArray: string[] = ["apple", "banana", "cherry"];
const numberArray: number[] = [1, 2, 3, 4, 5];

const size1: number = getSize(stringArray);
const size2: number = getSize(numberArray);

//(2) 유니온타입
function getSize2(arr:number[] |string[]):number{
    return arr.length;
}

const arr1=[1,2,3];
getSize2(arr1);
const arr2=["a","b","c"];
getSize2(arr2);

//(3) 제네릭
//<T> : 제네릭 타입 매개변수이며 T는 타입 변수로, 함수가 호출될 때 실제 타입으로 대체되고, 이를 통해 함수가 여러 타입에 대해 재사용 가능
//(arr: T[]): number: 함수의 시그니처로 함수의 매개변수와 반환 타입을 정의
function getSize3<T>(arr:T[]):number{
    return arr.length;
}
const arr3=[1,2,3];
getSize3<number>(arr3);
const arr4=["a","b","c"];
getSize3<string>(arr4);
const arr5=[true,true,false];
getSize3<boolean>(arr5);
const arr6=[{},{},{name:"Tim"}];
getSize3<object>(arr6);
const arr7=["abc",2,3];
getSize3<number|string>(arr7);

//인터페이스에서의 제네릭

//option 파라미터가 any타입인 인터페이스
interface Mobile2{
    name: string;
    price: number;
    option: any;
    //어떤 타입이든 가능한 any
}

//제네릭으로 변경 -> 한번 선언한 인터페이스로 각기 다른 모습의 객체 생성 가능
interface Mobile3<T>{
    //제네릭 인터페이스 정의이며 T는 타입 매개변수로 인터페이스를 사용할 때 실제 타입으로 대체
    name: string;
    price: number;
    option: T;
    //option을 제네릭 타입 T 속성으로 지정하겠다는 의미로 실제 사용할 때 동적으로 지정
}

//const m1: Mobile3<object>={
const m1: Mobile3<{color:string;coupon:boolean}>={
//옵션 객체를 직접 정의해줘도 된다.
//제네릭 타입의 실제 타입 전달
    name: "s21",
    price: 1000,
    option:{
        color:"red",
        coupon: false,
    },
};

const m2: Mobile3<string>={
    //제네릭 타입의 실제 타입 전달
    name: "s20",
    price: 1000,
    option: "good"
};


interface User7{
    name: string;
    age: number;
}

interface Car7{
    name: string;
    color: string;
}

interface Book7{
    price: number;
}

const user8: User7 ={name:"a", age:10};
const car8: Car7 ={name:"bmw", color:"red"};
const book8:Book7={price:3000};

//data가 any타입
// function showName4(data):string{
//     return data.name;
// }
//data를 제네릭타입으로
// function showName4<T>(data:T):string{
//     return data.name;
//     //모든 매개변수에 name이 있다고 장담 불가
// }

function showName4<T extends {name:string}>(data:T):string{
    //제네릭 타입으로 T를 쓰는데 이 함수를 호출하는 T는 반드시 name을 가진 객체를 확장한 형태이다
    //즉, 이 함수를 사용하는 경우, 전달되는 객체의 형태는 반드시 string 타입의 name 속성을 가져야 하는 제한조건을 명시한 것 -> 상한제한 (와일드카드나 하한제한 문법은 존재X)
    return data.name;
    //모든 매개변수에 name이 있다고 장담 불가
}
showName4(user8);
showName4(car8);
//showName4(book8);
//name이 없거나 string이 아니므로 에러발생
반응형