본문 바로가기
tsc

타입스크립트 / generic

by Box 2022. 2. 2.
728x90

제너릭 [ Generic ]

선언 시점이 아니라 생성 시점에 타입을 명시하여 하나의 타입만이 아닌 다양한 타입을 사용할 수 있도록 하는 기법이다. 

데이터 타입을 정하지 않고 외부에서 지정하는 방법

여러 가지 타입에서 동작하는 컴포넌트를 생성하는데 사용

 

특징

컴파일시 타입 안정성을 보장한다.

캐스팅 관련 코드를 제거할 수 있다.

 

코드 예시

자료구조 클래스로 예를 들어보겠다.

class stack {
    private data: any[]= [];

    constructor(){}

    public push(item: any) {
        this.data.push(item)
    }

    public pop():any {
        return this.data.pop();
    }

    ...
}

export default stack

해당 자료구조엔 어떤타입이 들어갈지 모르기 때문에 any 타입을 명시하고 있다.

 

그런데 특정 타입에 대해서만 데이터를 관리하고 싶다면 다음과 같은 코드를 작성하게 된다.

class numberStack extends stack {
    constructor(){super()}

    public push(item: number) {
        super.push(item)
    }

    public pop():number {
        return super.pop();
    }
}

class stringStack extends stack {
    constructor(){super()}

    public push(item: string) {
        super.push(item)
    }

    public pop():string {
        return super.pop();
    }
}

타입 하나만 다를 뿐인데 이렇게 많은 코드를 작성해야되는건 비효율적이다.

 

이문제를 해결 하기위한것이 제너릭 을 활용하는것이다.

class stack<T>{
    private data: T[]= [];

    constructor(){}

    public push(item: T) {
        this.data.push(item)
    }

    public pop(): T | undefined {
        return this.data.pop();
    }

    ...
}

자료구조를 정의할 땐 외부에서 받도록한다.

const stackByNumber = new stack<number>();
stackByNumber.push(1)
stackByNumber.push(2)

const stackByString = new stack<string>();
stackByString.push("a")
stackByString.push("b")

제너릭을 이용해 하나의 자료구조로 여러타입을 관리할수있다.

 

타입 상속을 이용하는방법

제너릭도 하나의 타입이기 때문에 interface 처럼 상속이 가능합니다. 

상속을 위해 extends 문법을 사용한다.

 

function add<T>(a:T,b:T){
	return Number(a)+ Number(b);
}

let a = 2;
let b = 3;

let result = add<number>(a,b);

console.log(result)

해당 코드를 보면 Number(a) 이렇게 생긴 불필요한 캐스팅 코드가 들어간다.

타입 상속을 이용하여 바꿔보겠다.

function add<T extends number>(a:T, b:T){
	return a+ b;
}

해당 제너릭은 number 타입만 받을 수 있게됬다.

 

룩업 타입 ( Lookup type - keyof)

룩업 타입은 keyof 로 속성을 포함하는 대상을 찾아서, 유니언 타입처럼 동작한다.

interface exLookup{
	ex1 : number;
	ex2 : number;
	ex3 : number;
}

type useLookup = keyof exLookup;

위와 같이 구현하였을때, useLookup은 인터페이스 속성의 속성에 해당하는 ex1, ex2, ex3 값중 하나의 속성명만 허용한다.

let real: useLookup = "ex2";

함수에서 전달 받은 인자값을 받은 객체의 속성 값으로 제한하고 싶을때는 아래와 같이 설계하면 된다.

function getItem<T,K extends keyof T>(object:T, key:k){
	return object[key];
}

let arr = {"용":1, "앙":2};

console.log(getItem(arr, "앙")); // 2