ice rabbit programming

[JS][TS] Typescript에서의 Generic(Feat. keyof) 본문

Development/JavaScript

[JS][TS] Typescript에서의 Generic(Feat. keyof)

판교토끼 2020. 12. 28. 01:40

이번 글에서는 OOP에서 함수(메소드)와 클래스를 General하게 사용할 수 있는 Generic을 다룰 것이다. C#이나 자바의 Generic, C++의 Template 개념과 완전히 동일하다. 때문에 간단하게만 살펴보자. 타 언어에서 다루어보았다면 어렵지 않게 이해할 수 있을 것이다.

아래 함수 Generic의 예시를 보자.

function hello<T>(msg: T): T {
    return msg
}
hello('hi') // str
hello(35) // number

 

타 언어와 동일함을 볼 수 있다. T에 들어가는 type이 모든 T에 적용된다.

Union Type을 이용하여 제약을 줄 수도 있다. C#에서 generic - where 구문과 같다.

function hello<T extends string | number>(msg: T) : T {
    return msg
}

hello(3) // number OK
hello([3,5]) // Array No

 

함수 뿐 아니라 class에도 동일하게 적용이 가능하고, <T, K> 등 여러 개도 활용이 가능하다.

keyof

이어서 번외 개념으로 keyof 키워드를 한 번 보겠다. keyof는 Object의 key들의 lieteral 값들을 가져온다. 글로 읽으니 와닿지 않을 수도 있으니 다음 코드를 보자.

interface Person {
    name: string
    age: number
}

type Test = keyof Person // ("name", "age")

 

이 키워드를 Generic의 제한에도 활용이 가능하다. 이를테면 받은 인자의 literal 값을 이미 있는 것으로 제한하거나, 클래스의 멤버로 제한하고 싶은 경우이다. 이 역시 다음 코드를 보자.

function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]): void {
    obj[key]=value
}

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
    return obj[key]
}

setProperty(person, 'name', 'Anna')

 

위의 Person interface에 keyof를 가져오면 'name'과 'age'가 나온다. setProperty는 Person의 멤버 프로퍼티를 set하는 역할이므로, Person의 멤버를 넣어야 한다. 그러므로 Generic에 keyof를 통한 제한을 주는 것이다.

Generic과는 별개이지만, enum과 같이 keyof 키워드를 활용할 수도 있다.

const SUBJECT = {
    Math : 'Math',
    English : 'English',
} as const;
type SUBJECT = typeof SUBJECT[keyof typeof SUBJECT]; // 'Math' | 'English'

SUBJECT 객체에 typeof를 취하면 SUBJECT 자체가 나오고, 그에 keyof를 취하면 Math와 English가 나온다. 이것을 index로 하면 'Math'와 'English'가 나오게 되는데, 이것에 typeof를 취하면 literal type이 되므로, 이걸 Union한 타입이 type SUBJECT에 담기게 된다.

즉, enum과 같게 SUBJECT['Math']를 사용할 수 있는 것이다. 아래 링크는 본인이 처음 참고했던 글이고, 자세하게 정리되어 있으니 ts에서의 enum에 대해 더 궁금하신 분들은 이쪽으로
(참고 : engineering.linecorp.com/ko/blog/typescript-enum-tree-shaking/ )