Skip to content

Latest commit

 

History

History
108 lines (63 loc) · 3.6 KB

File metadata and controls

108 lines (63 loc) · 3.6 KB

1. 타입 변수 응용하기

4가지의 사례를 살펴보며 제네릭의 타입 변수를 더 잘 활용하는 방법에 대해 살펴봄

사례1

만약 2개의 타입 변수가 필요한 상황이라면 다음과 같이 T, U 처럼 2개의 타입 변수를 사용해도 됨

function swap<T, U>(a: T, b: U) {
  return [b, a];
}

const [a, b] = swap("1", 2);

→ T는 String 타입

→ U는 Number 타입


사례2

다양한 배열 타입을 인수로 받는 제네릭 함수를 만들어야 한다면 다음과 같이 할 수 있음

function returnFirstValue<T>(data: T[]) {
  return data[0];
}

let num = returnFirstValue([0, 1, 2]);
// number

let str = returnFirstValue([1, "hello", "mynameis"]);
// number | string

→ 함수 매개변수 data의 타입을 T[]로 설정했기 때문에 배열이 아닌 값은 인수로 전달할 수 없게 됨. 배열을 인수로 전달하면 T는 배열의 요소 타입으로 할당됨

→ 첫 번째 호출에서는 인수로 Number[] 타입의 값을 전달했으므로 이때의 T는 Number 타입으로 추론됨. 이때의 함수 반환값 타입은 Number 타입이 됨

→ 두 번째 호출에서 인수로 (String | Number)[] 타입의 값을 전달했으므로 이때의 T는 String|Number 타입으로 추론됨. 이때의 함수 반환값 타입은 String | Number 타입이 됨


사례3

위 사례에서 만약 반환값의 타입을 배열의 첫 번째 요소의 타입이 되도록 하려면 다음과 같이 튜플 타입과 나머지 파라미터를 이용하면 됨

function returnFirstValue<T>(data: [T, ...unknown[]]) {
  return data[0];
}

let str = returnFirstValue([1, "hello", "mynameis"]);
// number

→ 함수 매개변수의 타입을 정의할 때 튜플을 이용해 첫번째 요소의 타입은 T 그리고 나머지 요소의 타입은 …unknown[]으로 길이도 타입도 상관 없도록 정의함

→ 함수를 호출하고 [1, “hello”, “mynameis”] 같은 배열의 값을 인수로 전달하면 T는 첫 번째 요소의 타입인 Number 타입이 됨. 따라서 함수 반환값 타입 또한 Number 타입이 됨


사례4

타입 변수를 제한하는 사례. 타입 변수를 제한한다는 것은 함수를 호출하고 인수로 전달할 수 있는 값의 범위에 제한을 두는 것을 의미

다음은 타입을 적어도 length 프로퍼티를 갖는 객체 타입으로 제시한 예시임

function getLength<T extends { length: number }>(data: T) {
  return data.length;
}

getLength("123");            // ✅

getLength([1, 2, 3]);        // ✅

getLength({ length: 1 });    // ✅

getLength(undefined);        // ❌

getLength(null);             // ❌

→ 타입 변수를 제한할 때에는 확장(extends)을 이용함

T extends {length: number} 라고 정의함녀 T는 이제 {length: number} 객체 타입의 서브타입이 됨.

→ 즉, T는 무조건 Number 타입의 프로퍼티 length를 가지고 있는 타입이 되어야 한다는 것.


따라서 이렇게 extends를 이용해 타입 변수를 제한하면 아래와 같은 결과가 나타남

  • 1번 호출은 인수로 length 프로퍼티가 존재하는 String 타입의 값을 전달했으므로 허용
  • 2번 호출은 인수로 length 프로퍼티가 존재하는 Number[] 타입의 값을 전달했으므로 허용
  • 3번 호출은 인수로 length 프로퍼티가 존재하는 객체 타입의 값을 전달했으므로 허용
  • 4번 호출은 인수로 undefined을 전달했으므로 오류가 발생
  • 5번 호출은 인수로 null을 전달했으므로 오류 발생