지난 시간에는 타입의 import 와 export, namespace 에 대해 알아보았습니다. 이번 시간에는 타입을 파라미터로 입력하는 Generic 에 대해 알아보겠습니다.
아래처럼 배열의 첫 번째 요소를 반환하는 함수를 만들고, a를 출력해보면 예상대로 4가 나오지만, 수식 연산은 안됩니다. 왜냐하면 애초에 unknown 타입으로 지정했기 때문입니다.
function practice(x: unknown[]) {
return x[0];
}
let a = practice([4, 2]);
console.log(a + 1); //error 'a'은(는) 'unknown' 형식입니다.ts(18046)
해결책으로는, narrowing 을 사용하거나 assertion 을 하면 되는데, 그것보다는 파라미터로 타입을 입력하는 Generic 함수를 사용해도 됩니다. 함수 옆에 <> 로 작명을 아무렇게나 해주고, 함수를 사용할 때 타입을 파라미터로 명시하면 됩니다.
function practice<T>(x: T[]): T {
return x[0];
}
let a = practice<number>([4, 2]);
console.log(a + 1);
함수를 사용할 때는, 자동으로 유추해서 타입을 파라미터로 안넘겨줘도 되지만, 명시해주는 편이 좋습니다.
function practice<T>(x: T[]): T {
return x[0];
}
let a = practice([4, 2]);
console.log(a + 1);
이번에는 숫자를 집어넣으면 -1해서 return 해주는 함수를 만들어봅시다. 에러가 발생하는 것은, 함수 자체만 봤을 때 사용하는 곳에서 어떤 타입을 줄 지 불확실하기 때문입니다.
function practice<T>(x: T) {
return x - 1; //error
}
let a = practice<number>(100);
위의 경우도 narrowing 을 하면 되지만, 타입파라미터를 제한할 수 있습니다. extends 를 이용해 T가 우측에 있는 속성을 가지고 있는지 체크합니다.
function practice<T extends number>(x: T) {
return x - 1;
}
let a = practice<number>(100);
아래처럼 커스텀 타입으로도 타입파라미터의 제한이 가능합니다.
interface LengthCheck {
length: number;
}
function practice<T extends LengthCheck>(x: T) {
return x.length;
}
let a = practice<string>("100");
참고로 class도 타입파라미터의 지정이 가능하며, 타입변수도 가능합니다.
class Practice<T> {}
let practice = new Practice<number>();
type Age<T> = T;
연습으로 문자를 집어넣으면 문자의 갯수, array 를 집어넣으면 array 안의 자료의 갯수를 콘솔창에 출력해주는 함수를 만들어봅시다.
function practice<T extends string | string[]>(x: T) {
console.log(x.length);
}
practice<string>("hello");
practice<string[]>(["kim", "park"]);
data 라는 JSON 자료를 object 자료로 변환해서 return 해주는 함수를 만들기
변환된 object의 타입은 Animal이 되기
interface Animal {
name: string;
age: number;
}
let data = '{"name":"dog","age":1}';
interface Animal {
name: string;
age: number;
}
let data = '{"name":"dog","age":1}';
function practice<T>(x: string): T {
return JSON.parse(x);
}
let result = practice<Animal>(data);
console.log(result);
파라미터에 string을 집어넣으면 string
number를 집어넣으면 number
string[]을 집어넣으면 string[]
class Person {
name;
constructor(a) {
this.name = a;
}
}
let a = new Person("John");
a.name; // any type
class Person<T> {
name;
constructor(a: T) {
this.name = a;
}
}
let a = new Person<string>("John");
a.name; // any type
지금까지 타입을 파라미터로 입력하는 Generic 에 대해 알아보았습니다.