💻오늘 배운 내용
Generic
타입을 함수의 파라미터처럼 사용한다. (선언 시에는 타입 파라미터만 적어주고, 생성하는 시점에 사용하는 타입을 결정)
함수의 인자로 어떤 타입이 들어갔고 어떤 값이 반환되는지는 알 수 없을 때 유용하다.
예시코드
function getSize(arr:number):number{
return arr.length;
};
const arr = [1, 2, 3];
getSize(arr); //3
getSize라는 함수가 있고, 호출 시 인자로 숫자배열을 넣어준다고 치자.
파라미터의 타입은 넘버, 함수의 타입도 배열의 길이를 반환하기 때문에 넘버가 된다
하지만 여러 형태의 배열에서 쓰인다면 어떨까?
function getSize(arr : number[]): number {
return arr.length;
};
const arr1 = [1, 2, 3];
getSize(arr1); //3
const arr2 = ["a", "b", "c"];
getSize(arr2); //3
const arr3 = [true, false, false];
getSize(arr3); //3
const arr4 = [{}, {}, {name : "KIM"}];
getSize(arr4); //3
arr1을 제외하고선 죄다 에러가 뜰 것이다. 타입이 숫자배열이 아니니까.
그런 경우 함수 오버로딩이나 '|'를 이용하여 union타입으로 지정해 줄 수 있다.
function getSize(arr : number[] | string[] | boolean[] | object[]): number {
...생략
}
하지만 그렇게 되면 새로운 배열이 생길때 마다 계속 계속 추가해줘야 하는 단점이 생긴다.
이럴 때 사용하기 좋은 것이 generic이다.
function getSize<T>(arr : T[]): number {
return arr.length;
};
함수이름 옆에 <>를 이용하여 들어갈 인자를 적어준다. (보통 선언 시에 T를 많이들 사용한다.)
여기서 T는 어떤 타입을 전달 받아서 이 함수를 사용할 수 있도록 한다.
즉 getSize 함수의 매개변수 타입은 T의 배열이 된다.
그리고 사용 시점에 이 T가 어떤 타입인지 결정해주면 된다.
function getSize<T>(arr : T[]): number {
return arr.length;
};
const arr1 = [1, 2, 3];
getSize<number>(arr1); //3
const arr2 = ["a", "b", "c"];
getSize<string>(arr2); //3
const arr3 = [true, false, false];
getSize(arr3); //3
const arr4 = [{}, {}, {name : "KIM"}];
getSize(arr4); //3
실행 시 함수이름 옆에 타입을 특정해주면 되는 것.
하지만 사실 적어주지 않아도 타입스크립트는 전달되는 파라미터를 보고 어떤 타입인지 알 수 있다.
선언할 때 <T>라고 적어뒀으니까!
따라서 특정타입을 강제하고 싶은 경우에만 작성해도 상관없다.
인터페이스에서 generic 사용 할 때
interface Mobile {
name: string;
price: number;
option: any;
}
// 옵션에 어떤 타입이 들어오는지 모르는 상태일 때,
// 가능한 옵션의 타입을 모두 적어주는 것은 비효율적이니까 제네릭을 이용하면 좋다.
interface Mobile<T> {
name: string;
price: number;
option: T;
}
위 함수의 예시를 보자.
const m1: Mobile = {
name: "s21",
price: 1000,
option: {
color: "red",
coupon: false,
},
};
const m2: Mobile = {
name: "s20",
price: 900,
option: "good",
};
이 상태로는 m1, m2 둘 다 에러가 난다. 여기서 타입을 전달해 주어야 한다.
const m1: Mobile<object> = {
name: "s21",
price: 1000,
option: {
color: "red",
coupon: false,
},
};
// 혹은 옵션 객체의 모습이 정해져 있다면 Mobile<{color : string; coupon : boolean }>
// 이라고 적어줘도 무방하다.
const m2: Mobile<string> = {
name: "s20",
price: 900,
option: "good",
};
객체의 속성을 제약하는 방법
function getProperty<T, O extends keyof T>(obj: T, key: O) {
return obj[key];
}
let obj = { a: 1, b: 2, c: 3 };
getProperty(obj, "a"); // okay
getProperty(obj, "z"); // error: "z"는 "a", "b", "c" 속성에 해당하지 않습니다.
generic을 선언할 때 <O extends keyof T> 부분에서 첫 번째 인자로 받는 객체에 없는 속성들은 접근할 수 없게끔 제한할 수 있다.
🧐궁금점과 부족한 내용
실행 시 함수이름 옆에 타입을 특정해주지 않아도 타입스크립트는 전달되는 파라미터를 보고 어떤 타입인지 알 수 있다.
선언할 때 <T>라고 적어뒀으니까!
라고 앞서 말했었는데
특정타입을 강제하고 싶은 경우에만 작성해도 상관없다면 굳이 타입스크립트를 쓰는 이유가 있는가..
자바스크립트와 다른게 무언가~ 의문이 드는 것은 사실이다.
이 부분은 내일 튜터님 찾아가서 따로 한번 물어봐야겠다.
📋레퍼런스
[TypeScript] 타입스크립트 제네릭(Generic), Factory Pattern with Generics
'내일배움캠프 > Today I Learned' 카테고리의 다른 글
[TIL 2023.08.02] Next.js 기본 개념 (0) | 2023.08.02 |
---|---|
[TIL 2023.08.01] 자바스크립트로 만든 투두리스트 타입스크립트로 바꾸기 (0) | 2023.08.01 |
[TIL 2023.07.28] 타입스크립트 객체 지향 프로그래밍 (0) | 2023.07.31 |
[TIL 2023.07.27] 헷갈리는 용어들 개념 정리 (절차적 프로그래밍 vs 객체지향 프로그래밍 / 정적언어 vs 동적언어 / 함수 vs 메서드 / Parameter vs Property vs 인자 vs 생성자) (0) | 2023.07.27 |
[TIL 2023.07.26] 타입스크립트 enum과 object literal의 차이점 / 주요 유틸리티 타입 (0) | 2023.07.26 |