• 모닥위키모닥위키
  • 모닥위키
위키
  • 임의문서
  • 주간인기
  • 문서
  • 시리즈
    AAAdddvvveeerrrtttiiissseeemmmeeennntttAdvertisement

    © 2025 modak.wiki All rights reserved.

      타입 확장과 지네릭

      Chapter 2 - 확장과 동적 재활용을 위한 기능

      컴퓨터/IT학습
      lu

      luasenvy (luasenvy)

      CC BY 4.0 국제규약

      타입 캐스팅

      const variable: unknown = "hello";
      
      console.info((<string>variable).length);
      console.info((variable as string).length);
      

      타입 캐스팅을 통하여 unknown 타입을 string 유형으로 변환하는 예제이다. 캐스팅하지 않는다면 .length가 존재하지 않기 때문에 오류가 발생하지만 캐스팅을 통하여 컴파일러에게 해당 변수가 문자열임을 알려줄 수 있다.

      const num: number = 0;
      console.info(variable as string); // Error
      console.info(variable as unknown as string);
      

      타입 캐스팅은 호환되는 타입끼리만 가능하다. 위처럼 숫자형과 문자형은 서로 캐스팅할 수 없다. 그러나 강제로 하는 방법도 존재하는데 모든 자료형과 호환되는 unknown 타입으로 먼저 변환하고 다시 원하는 타입으로 변환하는 것이다. 자료형에 대한 정확성과 가독성이 낮아지므로 캐스팅은 최대한 피해서 작성하는 것이 좋다.

      특수 유형

      • any: 타입스크립트의 검사를 생략함
      • unknown: 어떤 값이 들어올지 알 수 없음.(모든 값이 허용됨)
      • undefined: undefined
      • never: 실행되지 않음
      • void: 반환값을 고려하지 않음

      any vs unknown

      any 타입은 타입스크립트의 검사를 생략하기 때문에 비권장되며 린터에서 오류를 발생시키기도 한다. 정말 특수한 경우가 아니라면 사용하지 않는 것이 좋다. 따라서 타입스크립트측에서도 any 보다는 unknown을 사용하여 우회하는 방법을 권장한다. 없는 문법이라고 생각하는 것이 프로그램의 오류를 줄이는 방법이다.

      never

      const onlyThrow = (): never => {
        throw new Error("Error");
      }
      
      const neverEnd = (): never => {
        whild(true) console.info("loop.");
      }
      

      조금 생소한 유형인데 인터프리터가 실행하지 못하는 경우 사용한다. 위 예시처럼 함수가 종료되지 않는 경우 인터프리터가 함수 종료를 절대로 실행할 수 없기 때문에 반환형을 never 타입으로 설정할 수 있다.

      void vs undefined

      언뜻 보면 void와 undefined는 동일한 작동을 하는 것처럼 보이고 undefined가 가독성을 떨어뜨려 별칭으로 void를 지원하는 것 아닌가 하는 기분이 든다. 그러나 작동 방식에 약간 차이가 있다. 위에서 설명했듯이 void의 경우 '반환형에 대해서 신경 쓰지 않겠다'는 이야기와 같다.

      type CallbackType = (el: number) => void;
      
      const arr = [1, 2, 3, 4, 5];
      const callback: CallbackType = (el) => ++el;
      
      arr.forEach(callback);
      

      위 예시는 아주 간단한 forEach를 작성해 본 것이다. 인자로 넘긴 함수는 배열을 순회하면서 요소들의 값을 1 증가시킨 후 반환하고 있다. forEach를 자주 써보면 알겠지만 이 인자로 넘기는 순회용 함수는 반환형이 뭐가 됐든 상관이 없다. Java나 C처럼 void가 '아무런 값을 반환하지 않는다'라는 의미와는 다르다.

      const fnUndefined = (): undefined => 3; // Error
      const fnVoid = (): void => 3;
      
      const noReturn = (): undefined => {}
      const noReturnRuntime = (): undefined => {
        return;
      }
      
      noReturn === noReturnRuntime // undefined === undefined -> true
      

      조금 다른 예시를 들어보자. void의 경우 생뚱맞게 숫자를 반환했음에도 오류없이 동작한다. '반환된 값을 특정할 수 없으니 되도록 사용하지 말아라'로 이해하는 것이 더 바람직하다고 생각한다. 자바스크립트는 함수가 종료될때까지 명시된 return 구문을 만나지 못하고 종료되면 undefined를 반환하게 되어있다. 함수의 가장 마지막 줄에 항상 return undefined; 코드가 생략 되어있다고 생각하면 된다.

      동적 필드 객체 타이핑

      /* type */
      type PlainObjectRecordType = {
        username: string;
      } & Record<string, unknown>;
      
      /* interface */
      interface PlainObjectRecord {
        username: string;
        [key: string]: unknown;
      }
      

      위 예제의 두 타입은 동일하게 작동한다. 객체의 멤버로 username 키가 문자열로 반드시 있어야 하고 다른 필드는 어떤 것이 들어올지 모르겠으나 허용하는 타입이다. 객체를 다루기 시작하면 점점 타입 선언이 길어지고 복잡해지는데 [key: string]: unknown보다는 Record<Key, Value> 방식이 조금 더 가독성이 좋아 더 선호된다. 그러나 피할 수 없는 케이스도 있을 수 있으므로 둘 다 알아두어야 한다.

      확장

      type User = { name: string };
      type ExtendUser = Param & { username: string }
      type NextExtendUser = ExtendUser & { password: string }
      
      interface User {
        name: string
      }
      
      interface ExtendUser extends {
        username: string
      }
      
      interface NextExtendUser extends {
        password: string
      }
      

      타입은 &를 사용하여 확장할 수 있고 인터페이스는 extends 문법을 활용하여 확장할 수 있다.

      지네릭

      type ConditionalTypeParamRequired<T> = Array<T>;
      type ConditionalTypeParamDefault<T = string> = Array<T>;
      type ConditionalTypeParamExtends<T extends string> = Array<T>;
      
      const generic: ConditionalTypeParamRequired<number> = [1, 2, 3, 4];
      const defaultGeneric: ConditionalTypeParamDefault = ["A", "B", "C"];
      const genericNotMatched: ConditionalTypeParamExtends<number> = [1, 2, 3, 4, 5]; // Error not 'string' type
      

      지네릭이라는 생소한 단어 때문에 이해가 잘 안될 수도 있지만 타입용 파라미터라고 부를 수도 있다. 그러나 지네릭이라는 용어가 타입스크립트뿐만 아니라 지네릭 문법을 지원하는 많은 언어들도 사용하는 용어이기 때문에 기억해두는 것이 좋다.

      지네릭을 사용하면 타입을 조금 더 동적으로 만들 수 있다. 지네릭을 통해 넘긴 타입형은 선언된 타입의 내부에서 모두 치환되어 동적으로 작동하게 된다. 지네릭은 기본값을 할당할 수도 있으며 extends문을 사용하면 넘겨받을 지네릭의 타입형을 제한할 수도 있다.

      type ConditionalGenericParamAndResponse = <T = string>(param: T): Array<T>;
      
      const getArray: ConditionalGenericParamAndResponse = (param) => [param];
      
      const result = getArray(1); // Array<number>
      const errors = getArray<boolean>(10); // Error
      

      지네릭은 함수에도 적용할 수 있는데 함수 파라미터와 연결하여 사용하면 지네릭이 파라미터의 타입형으로 설정되어 가독성과 함께 타입스크립트가 코드와 더 잘 어울리도록 구성할 수도 있다.

      초판: 2024. 08. 28. 16:51:51

      © 2024 이 문서는 "CC BY 4.0 국제규약" 라이선스로 배포 되었습니다. 모든 권리는 저자에게 있습니다.

      타입 확장과 지네릭

      타입 캐스팅
      특수 유형
      any vs unknown
      never
      void vs undefined
      동적 필드 객체 타이핑
      확장
      지네릭