[한입챌린지]타입스크립트 DAY5

Lina Hongbi Ko·2025년 3월 4일
0
post-thumbnail

DAY5

2025년 3월 1일

✨ 객체 타입의 호환성

  • 기본 타입간의 호환성

    • 특정 타입을 다른 타입으로 취급해도 괜찮은지 판단
  • 객체 타입간의 호환성

    • 어떤 객체 타입을 다른 객체 타입으로 취급해도 괜찮은지 판단
  • 객체 타입도 기본 타입처럼 슈퍼-서브 타입을 가짐
    e.g) Dog 타입의 값이 Animal 타입이 될 수 있지만(업 캐스팅), Animal 타입의 값이 Dog 타입이 될 수 없음(다운 캐스팅)

  • 객체 타입들이 어떤 기준으로 관계를 갖는가?

    • 프로퍼티를 기준으로 관계를 가짐!!
    • 코드를 보면, Dog 타입이 프로퍼티를 더 많이 가졌으니깐 슈퍼 타입이라고 생각할 수 있지만, 그렇지 않음!
    • 타입스크립트는 프로퍼티를 기준으로 타입을 정의하는 구조적 타입 시스템을 따름 -> 추가 프로퍼티가 없는, 즉 조건이 더 적은 타입이 슈퍼 타입이 됨!
  • Book 타입에 ProgrammingBook의 값을 넣는 것은 가능 (업캐스팅) 그런데, 초기화하려고 ProgrammingBook 타입의 객체의 프로퍼티들을 넣으려고 할 때는 안된다고 함

    • 초과 프로퍼티 검사라는 타입스크립트의 특수한 기능이 발동되어서임
    • 초과 프로퍼티 검사 : 변수를 초기화할 때, 초기화 하는 값으로 객체 리터럴을 사용하면 발동하는 검사
      • 객체의 타입 변수를 초기화할 때 객체 리터럴을 사용하면, 초과 프로퍼티(실제 타입에 정의해 놓지 않은 프로퍼티)를 작성하면 안되도록 막는 검사
      • 따라서, 주석 처리를 하거나 삭제해서 객체 타입에 정의된 프로퍼티만 넣을 수 있도록 해야함
  • 만약, 초과 프로퍼티 검사를 피하려면 새로운 변수를 만든후 원하는 타입의 값(변수)를 할당해서 초기화하도록 한다 (객체 리터럴을 사용하지 않았으므로 허용함)
    e.g) let book3: Book = programmingBook;

  • 함수의 매개변수에도 마찬가지임

    • 함수를 호출하고, 함수의 인수로 객체 리터럴을 사용했을 경우, 초과 프로퍼티 검사가 발동됨
    • 따라서, 함수의 인수로 객체를 전달할 때 서브 타입 객체를 넣고 싶다면, 객체 리터럴을 이용하는게 아니라 변수에 저장해뒀다가 인수로 변수를 전달해야함
  • 변수를 초기화하거나 매개변수에 전달할 때, 객체 리터럴을 사용하면 반드시 정의된 프로퍼티만 사용해야함

    /**
     * 기본 타입간의 호환성
     */
    
    let num1: number = 10;
    let num2: 10 = 10;
    
    num1 = num2; // 업캐스팅
    
    /**
     * 객체 타입간의 호환성
     * -> 어떤 객체타입을 다른 객체타입으로 취급해도 괜찮은가?
     */
    
    type Animal = {
      name: string;
      color: string;
    }
    
    type Dog = {
      name: string;
      color: string;
      breed: string;
    }
    
    let animal: Animal = {
      name: '기린',
      color: 'yellow'
    };
    
    let dog: Dog = {
      name: '돌돌이',
      color: 'brown',
      breed: '진도'
    };
    
    animal = dog;
    
    // dog = animal; 오류
    
    type Book = {
      name: string;
      price: number;
    };
    
    type ProgrammingBook = {
      name: string;
      price: number;
      skill: string;
    };
    
    let book: Book;
    let programmingBook: ProgrammingBook = {
      name: '한 입 크기로 잘라먹는 리액트',
      price: 33000,
      skill: 'reactJS',
    };
    
    book = programmingBook;
    // programmingBook = book; 오류
    
    /**
     * 초과 프로퍼티 검사
     */
    let book2: Book = {
      name: '한 입 크기로 잘라먹는 리액트',
      price: 33000,
      // skill: 'reactJS',
    };
    
    let book3: Book = programmingBook;
    
    function func(book: Book) {
      func({
        name: '한 입 크기로 잘라먹는 리액트',
        price: 33000,
        // skill: 'reactJS',
      });
      func(programmingBook);
    }
    

✨ 대수 타입

  • 여러 개의 타입을 합성해서 새롭게 만들어낸 타입
  • 합집합 타입과 교집합 타입이 존재함

📍 합집합 - uninon 타입

  • | 을 사용

  • | 를 이용해서 넣을 수 있는 타입은 무한대임

    /**
     * 1. 합집합 - Union 타입
     */
    
    let a: string | number | boolean | undefined | null | {};
    a = 1;
    a = 'hello';
    
    a = true;
    
    let arr: (number | string | boolean)[] = [1, 'hello', true];
    
    type Dog = {
      name: string;
      color: string;
    };
    
    type Person = {
      name: string;
      language: string;
    };
    
    type Union1 = Dog | Person;
    
    let union1: Union1 = {
      name: '',
      color: '',
    };
    
    let union2: Union1 = {
      name: '',
      language: '',
    };
    
    let union3: Union1 = {
      name: '',
      color: '',
      language: '',
    };
    
    // let union4: Union1 = {
    //   name: '',
    // }; 오류 발생

📍 교집합 - intersection 타입

  • & 를 사용

  • 기본 타입을 가지고 intersection 타입을 만들면, 웬만하면 다 never 타입임 (서로 공유하거나 겹치는 값이 없음)
    - 보통 intersection 타입은 객체 타입에 많이 사용함

  • intersection 타입을 만들 때, 각 객체의 프로퍼티가 하나라도 빠지면 오류가 발생함

  • 위에서 살펴본것 처럼, Dog 타입에도 해당 되어야하고, Person 타입에도 해당되어야 함!

    /**
     * 2. 교집합 - Intersection 타입
     */
    
    let variable: number & string;
    // number 타입과 string 타입의 교집합은 never -> 공집합
    
    type Dog = {
      name: string;
      color: string;
    };
    
    type Person = {
      name: string;
      language: string;
    };
    
    type Intersection = Dog & Person;
    
    let intersection1: Intersection = {
      name: '',
      color: '',
      language: '',
    };

✨ 타입 추론

  • 타입스크립트는 점진적 타입 시스템임
    • 타입을 정의하지 않고, 초기값만 할당해줘도 알아서 타입스크립트가 초기값을 기준으로 변수의 타입을 추론함
  • 타입스크립트는 자동으로 변수의 타입을 추론함
    • 타입 추론을 잘 이용하면, 굳이 타입을 일일이 변수에 정의하지 않아도 되어서 타이핑 양이 줄어듦
    • 한가지 주의할 점은 모든 상황에서 타입스크립트가 타입을 잘 추론하지는 않음
      • 함수의 매개변수의 타입을 정의해주지 않으면 타입스크립트가 추론할 수 없음

📍 타입스크립트가 타입을 잘 추론하는 상황

  1. 일반적인 변수 선언
  • 초기값을 기준으로 타입을 추론

    • 객체를 구조 분해 할당할때에도 변수의 타입을 잘 추론하는 것을 볼 수 있음
    • 마찬가지로, 배열도 구조 분해 할당 해도 각각의 원소가 타입 추론이 잘되는 것을 확인할 수 있음
    let a = 10;
    let b = 'hello';
    let c = {
      id: 1,
      name: '이정환',
      profile: {
        nickname:'winterlood',
      },
      urls: ['https://winterlood.com'],
    };
    
    let { id, name, profile} = c;
    
    let [one, two, three] = [1, 'hello', true];
    // [number, string, boolean]으로 타입을 추론함
  1. 함수의 타입 추론
  • 반환 값을 기준으로 타입을 추론

    • 함수의 매개변수에 기본값이 설정되어 있다면, 그 기본값을 기준으로 타입을 추론함
    function func(message = 'hello') {
      return 'hello';
    }
  1. 초기값이 없는 경우 = any 타입의 진화
  • 변수를 선언하고 초기값을 지정하지 않으면 '암묵적인 any 타입'으로 추론됨

    • 변수에 들어가는 값에 따라서 any의 타입이 진화함
  • 명시적으로 any 타입을 정의하는 것과는 다름

    • 명시적으로 :any를 지정해주면 아래의 오류가 발생한 메서드들이 모두 오류가 발생하지 않음
  • 암묵적으로 any 타입을 정의하면 타입이 계속 진화함

  • 그런데 암묵적으로 any 타입을 정의하면, 중간에 타입이 바뀔 수도 있고 다른 사람이 짠 코드면 그 변수의 타입을 내가 직접 알아맞춰야 하는 상황이 발생할 수도 있음 -> 따라서, 암묵적으로 any 타입을 추론하도록 하지 않도록 해야함!! (초기값이 없는 경우)

    let d;
    d = 10;
    d.toFixed(); // number 타입으로 진화
    // d.toUpperCase(); 오류 발생
    
    d = 'hello';
    d.toUpperCase(); // string 타입으로 진화
    // d.toFixed(); 오류 발생
  1. const로 변수 선언
  • const로 변수를 선언하고 초기값을 정의하면 (타입을 지정하지 않고) 그 값 그대로가 타입이 됨 (기본 타입)
    const num = 10; // 타입: 10
    const str = 'hello'; // 타입: 'hello'
    const arr = [1, 2, 3]; // 타입: number[]
    const arr2 = [1, 'hello', true]; // 타입: (number | string | boolean)[]
    const arr3 = [1, 2, 3] as const; // 타입: [1, 2, 3]
  1. 여러 가지 타입의 요소를 저장하는 배열 선언
  • 타입스크립트는 타입을 추론할 때, 모든 배열 요소들의 타입을 비교해서 최적의 공통 타입으로 추론함
    let arr = [1, 'string']; // (number | string)[]
  1. 타입 넓히기
  • 범용적으로 변수를 추론
  • const로 선언한 상수가 아니라면, 타입을 넓혀서 범용적으로 변수를 사용할 수 있도록 타입을 추론함
let a = 10;
a = 99;
a = -2;

// let으로 선언한 a 변수에 number 타입의 값이 될 수 있는 모든 숫자를 할당할 수 있음

const b = 100;
b = 20; // 오류 발생

const arr = [1, 2, 3];
arr = [3, 4, 5]; // 오류 발생

출처: 한 입 크기로 잘라먹는 타입스크립트

profile
프론트엔드개발자가 되고 싶어서 열심히 땅굴 파는 자

0개의 댓글