본문 바로가기

Front-End: Web/TypeScript

[코딩애플] ts part 2-7. Generic 함수

반응형

타입을 파라미터로 입력하는 Generic

함수에 타입도 파라미터로 입력 가능

array 입력하면 첫 자료 return 해주는 함수

function 함수(x: unknown[]) {
    return x[0];
}

let a = 함수([4,2]);
console.log(a); // 4

근데 a 타입은 unknown이다. 왜냐하면 우리가 그렇게 지정해놓았으니까.

함수에 x라는 변수를 만들 때 타입을 unknown이 가득한 array로 지정했으니까. 그 자료의 첫 번째 자료를 뽑아도 unknown이다.

타입스크립트에게 자동으로 타입변환을 기대하면 안된다. 숫자나오면 숫자로 타입변환 그런거 안해준다. unknown이면 평생 unknown이다.

a가 unknown 타입이라서 가끔 이런 문제가 발생한다.

console.log(a + 1); // Error!

왜냐면 a는 unknown이니까!

해결책

  1. narrowing하거나 as 쓰기 (근데 귀찮음)
  2. Generic 함수 만들기 (파라미터로 타입을 입력하는 함수)

Generic 함수 = 파라미터로 타입을 입력하기

입력한 MyType을 아무 데나 갖다 쓸 수 있다. input 혹은 output의 타입에.

function 함수<MyType>(x :MyType[]) :MyType {
    return x[0]
}

let a = 함수<number>([4,2]);

파라미터의 타입으로 <number>로 입력해서 MyType = number가 된다. 그래서 input과 output의 타입이 number가 된다.

이렇게 타입을 만들고 싶으면 <꺾쇠>를 작성하면 된다!

장점

  1. 확장성이 있다.

매번 다른 타입 출력 가능

function 함수<MyType>(x :MyType[]) :MyType {
    return x[0]
}

let a = 함수<number>([4,2]);
let b = 함수<string>(['4','2']);

근데 따로 꺾쇠로 타입을 작성하지 않아도 된다. 타입스크립트가 알아서 타입을 지정해준다.

let a = 함수([4,2]);
let b = 함수(['4','2']);

a와 b에 마우스를 각각 대면 타입으로 number, string이 뜬다.

근데 이렇게 하면 협업할 때 다른 사람들이 코드를 알아보기도 어려우니까 그냥 이왕이면 <꺾쇠>로 타입을 작성해주도록 하자.

타입파라미터 제한 두기

예제) 숫자 집어넣으면 -1해서 return 해주는 함수

function 함수<MyType>(x :MyType) {
    return x - 1;
}

let a = 함수<number>(100); // Error!: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.

왜 에러가 날까? x가 숫자가 아니라서 뺄셈을 할 수가 없다고 한다. 하지만 딱봐도 파라미터에 100이라는 숫자를 넣어줬는데.

숫자도 집어넣고 MyType 자리에 <number>도 집어넣어줬는데..

let a = 함수<number>(100) 을 주석처리해보자. 그래도 에러가 발생한다. 주석한 자리에 어떤 값이 와도 모두 오류가 발생한다.

오류가 발생하는 이유는 얘가 걱정이 너무 커서다. MyType 타입이 숫자가 아닐 수도 있는데 벌써 return x - 1이라고 뺄셈을 하고 있으니 '숫자가 안 들어오면 어쩌지?'하면서 걱정하느라 에러를 내뱉고 있는거다.

그럼 어떻게 할까? narrowing 해야지. 근데 이게 귀찮다? 그럴 때 파라미터를 제한할 수 있다.

function 함수<MyType extends number>(x :MyType) {
    return x - 1;
}

extends 우측에 있는 타입들로 제한을 둘 수 있다. 여기서 extends는 확장한다는 의미가 아니고, **MyType이 우측에 있는 속성을 가지고 있는지 체크한다**, 고 생각하면 된다.

커스텀 타입으로도 타입파라미터 제한가능

string, number 뿐 아니라 커스텀 타입을 넣을 수도 있다.

예제) string의 글자 수 또는 array의 자료 개수를 세는 함수

function 함수<myType extends string>(x :MyType){
	return x.length;
}

내가 만든 interface, alias를 갖다 쓸 수도 있다. 이렇게 쓰면 MyType이 LengthCheck 속성을 가지고 있는지 체크한다.

interface LengthCheck {
    length : number
}
function 함수<myType extends LengthCheck>(x :MyType){
	return x.length;
}

여기서 파라미터 타입으로 number를 주게 된다면?

let a = 함수<number>(100); // Error!

왜냐하면 length라는 속성이 없으니까 안된다.

string을 주게 된다면? String은 .length 속성이 있으니까 가능하다.

let a = 함수<string>('aa');
let a = 함수<string>(['aa']);

Recap

  1. 함수에 타입파라미터 넣을 수 있음 -> Generic 함수
  2. Generic 안에서 extends 키워드로 넣을 수 있는 타입 제한 가능
  3. class에도 타입파라미터 넣을 수 있음
반응형