데브코스 27일차 ( 24.11.19 화 ) - Typescript

워니·4일 전
1

Programmers Front-end

목록 보기
26/27

[Section 02] Typescript 기본


< 04. 타입 오퍼레이터(type operator) >

  • 연산자

1. or (|) 유니온 타입(union type)

  • 서로 다른 타입 중 한 개나 여러 타입을 하나의 변수에 할당할 수 있게 하는 것
    • 예시
        let value: number | string | boolean = 10;
        value = "a";
        value = true;
      
        let obj: { name: string; age: number } | { skill: string } = {
          name: "john",
          age: 20,
        };
        obj = { skill: "front" };
      
        let arr: number[] | string[] = [1, 2, 3];
        arr = ["a", "b", "c"];
      
        let mixArr: (string | number)[] = [1, "a", 2, "b"];
    • 예시) 매개변수에서 유니온 타입 사용
      function printValue(value: number | string): void {
          console.log(value);
        }
        printValue(10);
        printValue("a");
    • 예시) 반환 값의 타입에서 유니온 타입 사용
      function printValue2(
          value: number | string | boolean
        ): number | string | boolean {
          return value;
        }
        printValue2(10);
        printValue2("a");
        printValue2(true);
  • 유니온 타입 사용 시 주의할 점
    • 함수에 사용할 때는 매개변수가 특정한 타입으로 지정되어야 한다.
    • 지정되어 있지 않으면 어떤 타입이 올 지 모르기 때문에 오류로 판단
      • 예시) toUpperCase() 를 사용할 때 발생하는 오류
        let value: string | number = "hello, world";
          console.log(value.toUpperCase()); // HELLO, WORLD
          
        // 위의 코드를 함수로 만들면 오류가 남
        function printProcess(value: string | number): void {
          console.log(value.toUpperCase())
        }
         printProcess("hello, world") // 오류

1.1. 타입 가드 (Type Guard)

  • 코드에서 값의 타입을 좁히거나 확실하게 추론할 수 있도록 도와주는 방법
  • typeof , instanceof (instanceof는 뒤에서 배울 것임)
  • 예시) 타입가드를 활용하여 오류를 막는 예시
    function printProcess(value: string | number): void {
        // 타입 가드(Type Guard)
        if (typeof value === "string") {
          console.log(value.toUpperCase());
        }
      }
      printProcess("hello, world");
  • 예시) 추가적으로 숫자를 매개변수로 넣어 toFixed를 출력할 경우
    function printProcess(value: string | number): void {
        // 타입 가드(Type Guard)
        if (typeof value === "string") {
          console.log(value.toUpperCase());
        }
        // 타입 가드(Type Guard)
        if (typeof value === "number") {
          console.log(value.toFixed(2));
        }
      }
      printProcess("hello, world");
      printProcess(10);
  • 예시) if…else문을 활용하여 타입을 특정하게 지정하는 방법
    • 다만, 타입이 더 확장되었을 경우 사용에 주의해야 함

      function printProcess(value: string | number): void {
          // 타입 가드(Type Guard)
          if (typeof value === "string") {
            console.log(value.toUpperCase());
          } else {
            console.log(value.toFixed(2));
          }
        }
        printProcess("hello, world");
        printProcess(10);
  • 예시) 타입가드를 함수 안에서만 사용할 수 있는 것은 아님
    function printProcess(value: string | number): string | number {
        return value;
      }
    
      const value1 = printProcess("hello, world");
      const value2 = printProcess(10);
      // value1과 value2는 함수 실행 값에 따라 문자열이 될 수도 숫자가 될 수도 있다
    
      // 따라서 console.log(value1.toUpperCase())와 같이 사용할 수 없음
      if (typeof value1 === "string") console.log(value1);
      if (typeof value2 === "number") console.log(value2);

2. and (&) 인터섹션 타입(intersection type)

  • 여러 개의 타입을 모두 만족하게 지정할 때 사용
  • 기본 타입에는 사용할 수 없음
  • 예를 들어 문자열이면서 숫자인 타입은 없으므로 사용 불가
    • 예시) 사용 불가 예시
      // string과 number를 동시에 만족하는 것은 불가하므로 어떤 값도 할당 불가
        let value: string & number;
  • 객체에서 사용 (가장 기본적인 원리)
    • 예시) 객체에서 활용 예시
      // ex)
        let value: { name: string; age: number } & { skill: string } = {
          name: "john",
          age: 20,
          skill: "front",
        };
      
        // ex2) 같은 속성에 댜른 타입을 지정하면 충돌하게 됨
        let value2: { name: string; age: number } & { skill: string; name: number } =
          // name에 string과 number가 충돌
          // 인터섹션 타입을 사용할 때는 속성이 충돌되지 않게 개발자가 신경을 써야 함
          {
            // name:: "john",
            age: 20,
            skill: "front",
          };
      
        // ex3) 속성 안의 속성값에 대해 적용하면 병합이 됨
        let value3: { name: string; address: { city: string } } & {
          address: { zipcode: number };
        } = {
          name: "john",
          address: {
            city: "seoul",
            zipcode: 111,
          },
        };
  • 인터섹션 타입any와 결합하면 any로 평가됨
    • 예시) any와 결합이 되면 같이 결합된 것은 의미가 없어짐
      let value: { namd: string } & any = {
          name: "철수",
          age: 29,
        };
    • 예시) unknown인터섹션 타입과 함께 사용할 수 없음
      let value: { name: string } & unknown = {
          name: "철수",
        };
  • 인터섹션 타입never와 결합하면 모두 never로 평가됨
    • 예시)
      let value: { name: string } & never;

< 05. 함수 오버로드 >

  • 함수의 타입이 여러 개가 전달될 수 있을 때,
    여러 가지 타입의 매개변수를 받아서 함수를 좀 더 정밀하게 지정
  • 예시) 문자열 또는 숫자를 매개변수로 받는 함수
      function combine(a: number | string, b: number | string): number | string {
        // 타입스크립트는 문자열 + 숫자를 허용하지 않음
        // 자바스크립트는 이 경우 숫자를 문자열로 변환하여 문제 없이 문자열 결합을 시킴
        if (typeof a === "string" && typeof b === "string") return `${a}${b}`;
        if (typeof a === "number" && typeof b === "number") return a + b;
        throw new Error("Invalid arguments");
        // return `${a}${b}` 이걸로 조건이 만족되지 않을 땐 저 값을 반환시킬 수도 있음
      }
    
      const result = combine(10, "a");
      console.log(result);
  • 예시) 위 예시를 타입 가드로 해결
      function combine(a: number | string, b: number | string): number | string {
        if (typeof a === "number" && typeof b === "number") return a + b;
        else return `${a}${b}`;
      }
    
      const result = combine(10, "a");
      // 타입 가드
      if (typeof result === "string") console.log(result.toUpperCase()); //10A
  • 예시) 위 예시를 함수 오버로드로 해결
    // 함수 오버로드로 경우의 수를 좁혀줌
    // 해당 하는 경우를 직접적으로 적어준다
      function combine(a: number, b: string): string; // (1)의 오버로드 시그니처
      function combine(a: string, b: number): string; // (2)의 오버로드 시그니처
    
      function combine(a: number | string, b: number | string): number | string {
        if (typeof a === "number" && typeof b === "number") return a + b;
        else return `${a}${b}`;
      }
    
      const result = combine(10, "a"); // (1)
      const result2 = combine("a", 10); // (2)
      // 타입스크립트는 오버로드에 더 의존함
      // 따라서 number + number = string으로 오버로드 시그니처를 작성하면
      // string으로 판단하고 toUpperCase에 넣지만 숫자이므로 오류 발생
      console.log(result.toUpperCase()); // 10A
      console.log(result2.toUpperCase()); // A10
  • 예시) 함수 오버로드 다른 예시
      function printReturnValue(value: number): number;
      function printReturnValue(value: string): string;
    
      function printReturnValue(value: number | string): number | string {
        if (typeof value === "number") return value.toFixed(1);
        else return value;
      }
      const res = printReturnValue(10);
  • 예시) 옵셔널 파라미터가 있는 함수도 오버로드로 구체화할 수 있음
      function showInfo(name: string): string; // number가 없는 경우
      function showInfo(name: string, age: number): string; // number가 있는 경우
    
      function showInfo(name: string, age?: number): string {
        if (age) {
          return `Hello, ${name}, ${age}`;
        } else {
          return `Hello, ${name}`;
        }
      }
      console.log(showInfo("john"));
      console.log(showInfo("john", 20));

< 06. 타입 추론 (type inference)과 타입 표명 (type annotations) >

1. 타입 추론

  • 변수에 할당된 값을 보고 타입을 추론하여 적용시켜 주는 것
  • 변수를 선언할 때, 타입을 명시하지 않더라도 타입스크립트가 자동으로 타입을 추론하는 기능
  • undefined까진 추론해주지 않음
  • 매개변수에 기본값을 지정하면 타입추론이 된다.

2. 타입 표명

  • 타입을 직접적으로 명시해주는 것
  • 타입 추론의 반댓말
  • 타입추론이 문제가 되지 않으면, 굳이 타입 표명을 하지 않아도 된다. (강사님 의견)

3. 타입 별칭 (type alias)

  • 나만의 타입을 짓는 방법
  • type(키워드) + 타입명(첫 글자 대문자) = 타입
type MyTypeName = string | number | boolean;

type Person = { name: string; age: number };

4. 리터럴 타입

  • 값으로 추론을 해주는 것, const 사용하면 리터럴 타입으로 추론됨
  • 리터럴 타입은 기본 자료형만 가능, 참조 자료형은 값이 바뀔 수 있으므로 리터럴 타입이 추론 안 됨
  • 따라서 참조 자료형은 타입 표명으로 명시해줘야 한다.
profile
첫 시작!

0개의 댓글