📌 리터럴 타입 (Literal Type)

🔹 문자열 리터럴 타입

정해진 string 값을 가진 것

  • [예시 1] 기본
    /*
    const: 변하지 않는 값 선언
    let: 변할 수 있는 값 선언 */
    
    const userName1 = "Bob"; // 👈 문자열 리터럴 타입
    let userName2 = "Tom";
    
    /*
    각 변수에 hover시 나오는 타입: 
    userName1 - "Bob" (string이지만, 변할 수 없음 -> "Bob" 외 불가) 👈 문자열 리터럴 타입인 이유
    userName2 - string ("Tom"이지만, 바꿀 수 있음 -> 더 넓은 개념의 string) */
    
    userName2 = 3;
    /*
    [에러 발생]
    - 이유: 최초 할당 값이 string (타입 명시 안했어도) */
    // [해결 방법] 명시적으로 재작성 (숫자도 넣으려면)
    let userName2 : string | number = "Tom";
  • [예시 2] type으로 이넘과 비슷한 형태 제작 가능
    type Job = "police" | "developer" | "teacher";
    
    interface User {
      name: string;
      job: Job;
    }
    
    const user: User = {
      name: "Bob",
      job: "developer" // Job에서 선언한 string만 사용 가능. 그 외 입력 시, 에러 발생.
    }

🔹 숫자형 리터럴 타입

interface HighSchoolStudent {
  name: string;
  grade: 1 | 2 | 3; // 학년은 1,2,3만 입력 가능하면 됨.
}

📌 유니온 타입(Union Type)

타입 의미: A이거나 B이다 ( JS의 OR 연산자(||)와 같음 )

🔹 정의 방식

연산자 (|)를 이용 → 타입을 여러 개 연결하는 방식

🔹 예시 코드

function logText(text: string | number) {
  // ...
}
// text(함수의 파라미터)에는 문자열 or 숫자 타입 가능

🔹 장점

  • any 사용 시 → JS로 작성하는 것처럼 동작

    유니온 타입 사용 시 → TS의 이점을 살리면서 코딩 가능

  • 예시 코드

    // any를 사용하는 경우
    function getAge(age: any) {
      age.toFixed(); // 에러 발생. 숫자 관련 API를 작성 시, 코드 자동 완성 x (이유: age의 타입이 any로 추론)
      return age;
    }
    
    // 유니온 타입을 사용하는 경우
    function getAge(age: number | string) {
      if (typeof age === 'number') {
        age.toFixed(); // 정상 동작. 숫자 관련 API를 쉽게 자동완성 가능 (이유: age의 타입이 `number`로 추론)
        return age;
      }
      if (typeof age === 'string') {
        return age;
      }
      return new TypeError('age must be number or string');
    }

🔹 사용 시, 주의할 점

  • 인터페이스와 같은 타입을 다룰 때, 논리적 사고(유니온 타입은 OR, 인터섹션은 AND)를 주의

    타입들에 공통적으로 들어있는 속성에만 접근 가능

    • 별도의 타입 가드(Type Guard)를 이용하여 타입의 범위를 좁히지 않는 이상

    • 이유

      TS 관점에서는 어느 타입이 올지 알 수 x → 어느 타입이 들어오든 간에 오류가 안 나는 방향으로 타입을 추론

  • 예시

    interface Person {
      name: string;
      age: number;
    }
    interface Developer {
      name: string;
      skill: string;
    }
    function introduce(someone: Person | Developer) {
      someone.name; // O 정상 동작
      someone.age; // X 타입 오류
      someone.skill; // X 타입 오류
    }
    
    /*
    해설 :
    `introduce()` 함수의 파라미터 타입을 두 인터페이스들의 유니온 타입으로 정의함.
    → 유니온 타입은 A도, B도 될 수 있는 타입이라고 생각 가능
    → 인터페이스들이 제공하는 속성들인 `age`나 `skill`를 사용 가능할 것이라고 생각 가능
    → TS 관점에서는 `introduce()` 함수를 호출하는 시점에 둘 중 어느 타입이 올지 알 수 x
    → 어느 타입이 들어오든 간에 오류가 안 나는 방향으로 타입을 추론
    */
    const capt: Person = { name: 'capt', age: 100 };
    introduce(capt); // 만약 `introduce` 함수 안에서 `someone.skill` 속성을 접근하고 있으면 함수에서 오류 발생
    
    const tony: Developer = { name: 'tony', skill: 'iron making' };
    introduce(tony); // 만약 `introduce` 함수 안에서 `someone.age` 속성을 접근하고 있으면 함수에서 오류 발생
    // name(두 타입의 공통 속성)만 접근 가능
    function introduce(someone: Person | Developer) {
      console.log(someone.name); // O 정상 동작
    }

🔹 식별 가능한 유니온 타입

동일한 속성의 타입을 다르게 해서 구분 가능

  • 검사 항목 수에 따른 추천 조건문 (가독성 용이)

    • 적은 경우 : if
    • 많은 경우 : switch

▼ 예시 코드

  • 인터페이스 선언
    interface Car {
      name: "car";
      color: string;
      start(): void;
    }
    
    interface Mobile {
      name: "mobile";
      color: string;
      call(): void;
    }
  • 문제
    function getGift(gift: Car | Mobile) {
      console.log(gift.color); // [문제 無] 이유: 둘 다 색상 보유.
      gift.start(); // [에러 발생]
    }
    /*
    에러
    - 메세지: Car 또는 Mobile 에는 start가 없다. (즉, Car만 start 함수 보유)
    - 해결 방법: start 사용 전, Car인지 먼저 확인 */
  • 해결
    function getGift(gift: Car | Mobile) {
      console.log(gift.color);
    
      // [해결] 식별 가능한 Union Type 사용
      if (gift.name === 'car'){
        gift.start(); // gift에 호버 시, Car로 파악함.
      } else {
        gift.call(); // gift에 호버 시, Mobile로 파악함.
      }
    }
    
    /*
    각 인터페이스의 name 속성 타입
    - Car: "car" 타입
    - Mobile: "mobile" 타입 (string 타입 아님.) */

📌 인터섹션 타입(Intersection Type)

여러 개의 타입을 하나로 합쳐주는 역할. (AND를 의미)

  • 필요한 모든 기능을 가진 하나의 타입이 만들어짐.

🔹 정의 방식

  • 연산자(&) 이용

  • 모든 속성 기입 필수

    → 다 적을 때까지 에러 안 사라짐.

    → 공통된 속성은 1번만 선언.

🔹 예시 코드

  • 1번 예시 (변수 할당)
    interface Car {
      name: string;
      start(): void;
    }
    
    interface Toy {
      name: string;
      color: string;
      price: number;
    }
    
    const toyCar: Toy & Car = {
      name: "타요", // 한 번만 선언
      start(){},
      color: "red",
      price: 1000,
    }
  • 2번 예시 (type)
    interface Person {
      name: string;
      age: number;
    }
    interface Developer {
      name: string;
      skill: number;
    }
    type Capt = Person & Developer;
    // Person 인터페이스의 타입 정의와 Developer 인터페이스의 타입 정의를 합친 후(& 연산자 이용) Capt 타입에 할당
    
    // Capt의 타입
    {
      name: string;
      age: number;
      skill: string;
    }

참고

  • 캡틴판교_타입스크립트 핸드북
  • 코딩앙마_타입스크립트
profile
복습 목적 블로그 입니다.

0개의 댓글