솔미는 성장중

[TS 2주차] 제네릭이란 무엇인가! (+ 제네릭을 제한하려면..?) 본문

TypeScript

[TS 2주차] 제네릭이란 무엇인가! (+ 제네릭을 제한하려면..?)

solming 2023. 8. 23. 11:48
728x90

제네릭은 카멜레온 같은 아이라고 생각하면 된다.

받은 타입을 그대로 반환한다! 라는 컨셉

 

📌 기본 문법

//함수
function testGeneric<T>(text: T):T{
  return text;
}
testGeneric<string>('hello world'); //hello world
//위 코드는 function testGeneric(text: string):string { } 과 동일하다.
testGeneric<number>(3); //3

//인터페이스
interface Dropdown<T>{
  value: T;
  selected: boolean;
}
let product: Dropdown<string>;
let stock: Dropdown<number>;
let address: Dropdown<{city:string, zipCode:string}>;

 

📌 언제 사용하면 좋을까?

함수의 역할과 동작은 같은데 타입을 여러 종류로 넣고 싶을 때!

타입별로 함수를 여러개 만드는 것 보다 제네릭을 쓰는게 효율적이다.

 

any로도 위 기능을 하도록 만들 수 있지만 자동완성 or 에러 사전 방지를 지원하지 않기 때문에 비추! 

 

 

📌 나는 제한을 좀 두고 싶은데? (feat. 제네릭의 타입 제한)

extends

예제1. 제네릭 타입을 숫자로 제약하기 (위 아래 같은 의미)

//제네릭 타입
function limitType<T extends number>(test: T): T {
  return test;
}
//기존 타입 설정
function limitType(test: number): number {
  return test;
}

 

예제2. length 속성을 갖는 타입만 사용 가능하게 제약

: string, array, object만 사용 가능.

function lengthOnly<T extends { length: number }>(value: T) {
  return value.length;
}
lengthOnly('hi');
lengthOnly([4,5,6,7]);
lengthOnly({name:'abc',length:100});

=>  value의 타입은 number 타입인 length를 담은 객체를 확장한 형태이다.

 

~~ 위 예제가 이해가 안되거나 자세한 설명을 원한다면 '더보기' 참고 ~~

더보기

1. { length: number }객체의 형태를 나타내는 타입이다.

 

2. 이 객체 내부에는 length라는 속성 이름과 그에 해당하는 값의 타입인 number가 선언되어 있다.

 

3. 즉, "객체의 속성 중에 length라는 속성이 있으며, 그 값은 숫자(number) 타입이어야 한다"는 제약을 의미

 

4. 문자열, 배열은 '.length' 속성이 내장되어있다. + 위 예제에서 마지막줄엔 length 속성을 만들어주었다.

 

5. 문자열:
 - 
JavaScript에서 문자열 데이터('hi'와 같은)는 내장된 String 객체의 인스턴스로 간주한다.

 - 이러한 String 객체는 .length와 같은 내장된 속성과 메서드를 가지고 있다.

 - 따라서 'hi'라는 문자열 데이터도 실제로 String 객체의 인스턴스이며, .length 속성을 통해 해당 문자열의 길이에 접근할 수 있다.

 - TypeScript에서는 이러한 내부적인 동작을 고려하여, 문자열 데이터 역시 String 객체의 인스턴스로 취급한다.

 - 따라서 { length: number }와 같은 타입을 가지는 객체로써 { length: 2 }와 같이 문자열 데이터 역시 처리할 수 있다.

 - TypeScript의 타입 시스템이 내부적으로 문자열 데이터와 문자열 객체의 속성과 메서드를 감지하여 이런 호환성을 제공하는 것 ! 결국 'hi'가 문자열 데이터임에도 불구하고 TypeScript는 이를 { length: number }와 같은 타입으로 간주하여 lengthOnly 함수와의 호환성을 유지시켜준다. 이는 TypeScript의 특별한 동작 방식으로 보면 된다.

 

6. 배열:

  배열은 객체의 일종이고, '.length'속성을 갖고 있어서 정상 작동

 

7. 객체:
  {length: number}를 확장한 {name:string, length:number}의 형태이기 때문에 정상 작동


 

 

extends와 함께 keyof를 쓴다면?

keyof 란?

: 특정 타입의 키 값을 추출해서 유니언 타입으로 변환해준다

 

예시) 위 아래가 같은 의미

type User = keyof {name: string; age:number;}
type User = "name" | "age"

 

extends와 keyof을 함께 쓴 예시

function printKeys <T extends keyof {name:string; age:number;}>(value:T){
  console.log(value);
}
//아래 예시만 오류없이 작동
printKeys('name')
printKeys('age')

 

 

 

728x90