문가가 공부한 기록입니다. 부정확한 내용은 편히 지적 부탁드립니다.
//call signature
type SuperPrint = <T>(a: T[]) => T
const superPrint: SuperPrint = (a) => a[0]
const a = superPrint([1, 2, 3, 4]);
const b = superPrint([true, false, false]);
const c = superPrint(["1", "2", "3"]);
const d = superPrint([1, 2, true, false, "무야호"]);
console.log(a, b, c, d); // 1 true 1 1
제네릭(Generics)은 기본적으로 placeholder를 사용해 코드의 타입을 우리가 작성한 코드의 타입 기준으로 바꿔준다. 이 말은 즉, 타입스크립트는 우리의 코드를 보고 타입을 알아낸다는 것이다. 소오름!!
그런데 누군가는 말할 수 있다. 아 그러면 그냥 타입에 any 박으면 되는 거 아닌가요오오?? 에러도 안 나는데???
//call signature
type SuperPrint = (a: any[]) => any;
const superPrint: SuperPrint = (a) => a[0];
const a = superPrint([1, 2, 3, 4]);
const b = superPrint([true, false, false]);
const c = superPrint(["1", "2", "3"]);
const d = superPrint([1, 2, true, false, "무야호"]);
console.log(a, b, c, d); // 1 true 1 1
위와 같이 any를 갈겨버리게 되면 타입스크립트는 더 이상 우리를 지켜주지 못한다. a, b, c, d 모두가 any기 때문이다. 무슨 말이냐고?
예를 들어 d.toUpperCase()를 사용하게 되면 에러가 난다. 왜냐면 superPrint는 배열의 첫 번째 요소를 리턴해주는데 d의 첫번째 요소는 number이다. 안타깝지만 숫자는 대문자가 없거든요. 아무튼 any 웬만하면 쓰지 말란 말이야~~
제네릭은 우리가 요구한 대로 signature를 생성해줄 수 있는 도구라고 생각하면 된다. 기억하자! 우리가 작성해야 할 Call signature를 생각하기 전에 타입스크립트가 우리를 위해서 우리의 코드를 공부할 것이다.
이제 superPrint 타입에 제네릭을 하나 더 추가하고 싶다고 해보자. 어떻게 해야 할까? 아주 쉽다.
//call signature
type SuperPrint = <T, M>(a: T[], b:M) => T;
const superPrint: SuperPrint = (a) => a[0];
const a = superPrint([1, 2, 3, 4]);
const b = superPrint([true, false, false]);
const c = superPrint(["a", "2", "3"]);
const d = superPrint([1, 2, true, false, "무야호"]);
제일 먼저 해야할 일은 , 제네릭을 사용할 것이라고 말해주고 이름을 작성하면 된다. 이름은 무엇이든 관계없다.(M, T, V 등등) 그리고 우리가 어디에서 이 제네릭을 사용할 것인지 말해주면 된다.(위의 경우는 두 번째 인자 b를 M으로 설정했다.) 타입스크립트는 제네릭을 처음 인식했을 때와 제네릭의 순서를 기반으로 제네릭의 타입을 알게 된다. 그리고 우리의 요구에 따라서 각기 다른 Call signature를 생성한다.
+참고자료
https://nomadcoders.co/typescript-for-beginners/lectures/3676
댓글