Generic
function 함수(x: unknown[]) {
return x[0];
}
let a = 함수([4,2])
console.log(a)
위와 같은 코드를 보자.
unknown 타입의 array 자료를 입력하면, array의 맨 앞 첫번째의 요소를 리턴해주는 함수가 있다고 해보자.
console.log 로 콘솔에 찍힌 a 의 타입은 뭘까?
unknown 이다.
입력하는 array 도 unknown 타입이기 때문이다.
function 함수(x: unknown[]) {
return x[0];
}
let a = 함수([4,2])
console.log(a + 1)
때문에 이런 경우에는 에러가 날 것이다.
왜냐하면 a 는 unknown 타입인데, 숫자인 1을 더하려고 했기 때문이다.
이런 문제를 해결하려면 narrowing 을 잘하면 되긴하지만,
애초에 타입을 파라미터로 함수에 미리 입력할 수도 있다.
이것을 Generic 이라고 부른다.
아래에서 예시를 살펴보자
function 함수<MyType>(x: MyType[]) :MyType {
return x[0];
}
let a = 함수<number>([4,2])
let b = 함수<string>(['kim', 'park'])
함수 옆에 < > 안에 type 을 넣으면 이 타입이 함수내에서 일종의 변수처럼 쓰일 수 있다.
예를 들어서 함수<number> 로 하면
MyType 자리에 number 가 들어가기 때문에 함수의 파라미터과 리턴값 모두 number 타입으로 지정이 되는 것이다.
function 함수<MyType>(x: MyType[]) :MyType {
return x[0];
}
let a = 함수([4,2])
let b = 함수(['kim', 'park'])
함수를 사용할 때 <> 안써도 기본타입을 유추해주기는 한다고 한다.(결과는 같음)
보통 타입 파라미터는 <T> 라고 많이들 쓴다고 한다!
그리고 타입 파라미터는 2개 이상 넣을 수도 있다.
Generic 타입 제한하기 (extends)
function 함수<MyType>(x: MyType) {
return x - 1
}
let a = 함수<number>(100)
이런 예제를 보자.
MyType 자리에 number 를 집어 넣어도 x-1 부분에서 에러가 난다. 왜일까?
왜냐하면 MyType에 number 외에 string 같이 다른 타입을 넣을 수 있어서 미리 방지를 해주는 것이다.
이럴땐 extends 키워드를 사용해서 MyType 에 집어넣을 수 있는 타입을 제한할 수도 있다.
function 함수<MyType extends number>(x: MyType) {
return x - 1
}
let a = 함수<number>(100)
위 코드에서 MyType 은 number 를 extends 한다 라고 적어주었다.
이렇게 되면, MyType 에는 number 타입만 들어갈 수 있게 제한할 수 있다.
interface lengthCheck {
length : number
}
function 함수<MyType extends lengthCheck>(x: MyType) {
return x.length
}
let a = 함수<string>('hello') //가능
let a = 함수<number>(1234) //에러남
위는 응용한 예제이다.
lengthCheck 이라는 interface 에서 length 는 숫자 타입이라고 지정했다.
이 상태로, MyType 은 lengthCheck 을 extends 한다고 했다.
이 말은 즉슨, MyType 도 length 속성을 복사해서 가지는 것이다.
따라서 MyType 은 length가 분명히 있기 때문에 x 는 .length 의 조작이 가능하다고 한다.
응용 예제
interface Animal {
name : string;
age : number
}
let data = '{"name" : "dog", "age" : 1 }'
data 라는 변수에 JSON 자료가 담겨있다.
이 JSON 자료를 object{ } 자료로 변환해서 리턴하는 함수를 만들어보자.
변환된 object 의 타입은 Animal 이 되어야 한다.
interface Animal {
name : string;
age : number
}
let data = '{"name" : "dog", "age" : 1 }';
function 함수<Type>(x :string) :Type {
return JSON.parse(x);
}
let result = 함수<Animal>(data)
console.log(result)
입력은 string 으로 받지만 Animal object 로 변환되도록 하는 함수를 구현한 모습이다.
class Person <T> {
name;
constructor(a :T){
this.name = a;
}
}
let a = new Person<string>('어쩌구');
a.name //string 타입
위 예제는 Person 클래스의 객체를 만들 때 파라미터에 타입을 입력하도록 만들었다.
따라서 객체의 name 이라는 속성은 입력한 타입을 가지게 된다.
(this.name 에 T 타입의 a 가 들어가기 때문)
ref: 코딩애플