WEB/TypeScript
[TypeScript] 제네릭 (함수/클래스/인터페이스, 제약 조건)
devOhzl
2024. 8. 26. 23:12
제네릭 (Generic)
함수, 클래스, 인터페이스에서 사용 가능하다.
타입 변수 부분에 제약 조건도 활용 가능하다.
함수
함수 이름 뒷 쪽에 대문자 T 로 타입 변수를 지정을 할 수 있다.
함수를 호출할 때 타입을 넣어줄 수도 있지만, 첫번째 인수를 통해 타입추론이 가능하게 사용할 수도 있다.
예제로 함수에서 제네릭 문법 사용하기
interface Obj {
x: number
}
type Arr = [number, number]
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: any, b: any) {
return [a,b]
}
console.log(
toArray('Neo', 'Anderson'), //[ 'Neo', 'Anderson' ]
toArray(1,2), // [ 1, 2 ]
toArray(true, false), // [ true, false ]
toArray({ x:1 }, { x:2 }), // [ { x: 1 }, { x: 2 } ]
toArray([1,2],[3,4]) // [ [ 1, 2 ], [ 3, 4 ] ]
)
위의 예제를 toArray를 함수를 다르게 사용할 때마다 오버로딩을 시킬 수는 없으므로 제너릭 문법으로 개선한다.
interface Obj {
x: number
}
type Arr = [number, number]
function toArray<T>(a: T, b: T) {
return [a,b]
}
console.log(
toArray('Neo', 123), // error! 알 수 없는 T 타입이 string이 되었다
toArray<string>('Neo',123), // error! T 타입을 string으로 지정하였다.
toArray(1,2), // [ 1, 2 ]
toArray<number>(1,2), // [ 1, 2 ]
toArray(true, false), // [ true, false ]
toArray({ x:1 }, { x:2 }), // [ { x: 1 }, { x: 2 } ]
toArray([1,2],[3,4,5]) // [ [ 1, 2 ], [ 3, 4, 5 ] ] , number[] 이 되므로 에러 발생 X
toArray<Arr>([1,2],[3,4,5]) // error! 튜플 타입이 되므로 5를 제거해야됨
)
타입 추론은 최대한 활용하는 것이 좋으므로 <string> 이나 <number>은 생략 가능하다.
클래스
클래스의 이름 뒤에 <> 를 열고 닫아 타입 별칭을 지정한다.
class User<P> {
constructor(public payload: P)
getPayload() {
return this.payload
}
}
/*
위의 코드는 아래의 코드 정리한 것임
class User<P> {
public payload: P
constructor(payload: P){
this.payload = payload
}
getPayload() {
return this.payload
}
}
*/
User 클래스 생성자를 호출하면 특정한 타입 P를 받는다,
payload 는 매개변수이면서 내부 속성이므로 this 키워드로 접근 가능하며, 타입을 지정한다.
클래스에서 제네릭 문법을 사용해보자
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 ohzl = new User<UserAType>({
name: 'ohzl',
age: 27,
isValid: true,
emails: [] // error! UserAType과 일치하지 않으므로 할당 불가능
})
const ohzl2 = new User<UserBType>({
name: 'ohzl',
age: 27,
emails: ['kar2125@naver.com']
})
인터페이스
사용방법은 클래스와 같다.
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: true
}
const dataD: MyData<number[]> = {
name: 'Data D',
value: [1,2,3,4]
}
제약 조건(Constraints)
타입 변수에 제약 조건을 넣을 수 있다.
타입 변수 T에 허용할 수 있는 타입을 지정한다.
interface MyData<T extends string | number[]> {
name: string
value: T
}
const dataA: MyData<string> = {
name: 'Data A',
value: 'Hello world'
}
const dataB: MyData<number> = { // error! 타입에는 sting이나 number만 가능하다.
name: 'Data B',
value: 1234
}
const dataC: MyData<boolean> = { // error! 타입에는 sting이나 number만 가능하다.
name: 'Data C',
value: true
}
const dataD: MyData<number[]> = {
name: 'Data D',
value: [1,2,3,4]
}