유니언과 리터럴

Kaia·2023년 8월 11일

typescript

목록 보기
3/4
post-thumbnail
💡 타입스크립트가 추론을 수행하는 두가지 핵심 개념에 대해 알아보자

[1] 유니언

허용된 타입을 두 개 이상의 가능한 타입으로 확장하는 것

let a: string | number;

  • 값이 어떤 타입인지 정확히는 모르지만 두개 이상의 옵션 중 하나이다!
  • 초기값(즉 초기 타입)이 있더라도, 명시적으로 선언이 필요한 경우에도 사용 가능
    let name: string | null = null; // 순서는 상관 없음
  • 유니언으로 선언한 타입 모두에 접근 가능한 멤버 속성만 접근할 수 있다.
    let name = Math.random() > 0.5
    	? 'jumi'
    	: 100;
    
    name.toString(); // ? o
    name.toUpperCase(); // ? num -> error
    name.toFixed(); // ? o str -> error

[2] 내로잉

타입가드를 통해 허용된 타입이 하나 이상의 가능한 타입이 되지 않도록 좁히는 것

타입을 좁히는데 사용할 수 있는 논리적 검사

  • 값 할당을 통한 내로잉
    let a: string | number;
    **a = 'a'; // 내로잉**
    
    a.toUpperCase(); // OK
    a.toFixed(); // error
  • 조건검사를 통한 내로잉
    • if 문을 통해 조건 검사

      let name = Math.random() > 0.5
      	? 'jumi'
      	: 100;
      
      if(name === 'jumi'){ // str
      	name.toUpperCase(); // 타입은 str? 에러여부는? x
      };
      
      name.toUpperCase(); // 타입은 string | number ? 에러여부는? error
  • typeof검사를 통한 내로잉
    • typeof 연산자를 사용해 타입을 좁힘

      let a: string | number;
      if(typeof a === 'string' 내로잉){
       // str
      };
      // str

[3] 리터럴

일반적인 원시타입 대신 특정 원시 값으로 타입을 정의하는 것이며, 원시 타입은 해당 타입의 무수히 많은 리터럴 값의 집합이다.

  • 변수를 const로 선언하고 직접 리터럴 값을 할당하면 타입스크립트는 해당 변수를 할당된 리터럴 값으로 유추
    const a = 'a';
    // const a: 'a';
  • 유니언 타입 애너테이션에서는 리터럴 타입과 원시 타입을 섞어서 사용할 수 있음
    let a: number | ‘a’ | ‘b’;
    
    a = 100; // OK
    a = 'a'; // OK
    a = 'c'; // error

할당 가능성

(1)지정된 원시타입 외 다른 타입은 할당이 불가능하며,

(2)동일한 원시 타입 일지라도 지정된 타입과 다른 리터럴 타입은 할당되지 않음

(1)let a: number;
(2)let a: ‘a’ | ‘b’;

a = 100; // OK
a = 'a'; // OK
a = 'c'; // error

그러나! 리터럴 타입은 그 값이 해당하는 원시 타입에 할당할 수 있다.

  • 모든 특정 리터럴 문자열은 여전히 string 타입
let a: 'a';
a = 'a'; // ? o
a = 'b'; // ?  error

let e = ''; // let e: string;
a = e; //  error
**e = ':)' // ? o -> OK**

[4] 확장

엄격한 null 검사

  • 타입시스템 영역 중 하나로, 잠재적으로 정의되지 않은 undefined 값으로 작업하는 경우 특히 사용됨
  • 타입스크립트에서는 일반적으로 엄격한 null 검사를 허용하는 것이 모범사례다.
    • null 또는 undefined 값으로 인한 오류로 부터 안전한지 확인
    • 다음 코드에서 발생할 잠재적 충돌 방지
// C++, Java 등에서는 허용됨
const name: string = null;

// typescript
// set tsconfig.json > strictNullCheck true
let nameMaybe = Math.random() > 0.5
	? 'jumi'
	: undefined;

nameMaybe.toUpperCase();
~~~~~~~~~
// (1) runtime error : cannot read property 'toUpperCase' of undefined
// (2) Error : Object is possibly 'undefined'

십억 달러의 실수
다른 타입이 필요한 위치에서 null 값을 허용하도록 하는 타입시스템을 가리키는 용어

참검사를 통한 내로잉

참 또는 truthy는 &&연산자 또는 if문처럼 boolean 문맥에서 true로 간주된다.

falsy = false, 0, -0, 0n, “”, null, undefined, NaN

빈 문자열의 경우 falsy로 판단될 수 있지만, 동시에 string 타입을 가질 수 있기 때문에 주의

// 만약 타입이 string | undefined 일 경우
let nameMaybe: string | undefined;

nameMaybe && nameMaybe.toUpperCase(); //OK
nameMaybe?.toUpperCase(); //OK

// nameMaybe가 falsy인 경우 빈문자열인지 undefined인지는 판단 불가

초기값이 없는 변수

변수에 초기 값이 할당되기 전에는 undefined 타입을 가짐

즉, 초기값 할당 전에 접근하는 경우에 변수 타입에 undefined 를 추가한다.

let name: string;

// 옵셔널 체이닝
// ?.은 ?.'앞’의 평가 대상이 undefined나 null이면 평가를 멈추고 undefined를 반환

name?.length; // err
name = 'jumi';
name.length; // OK
  • 답 error : ‘name’ is used before being assigned
    • 초기값 할당 전에 접근하는 경우에 변수 타입에 undefined 를 추가한다.

    • undefined 는 유효한 타입이기 때문에 이 경우에는 오류 보고 안함

      let name: string | undefined;
      
      name?.length; // OK
      name = 'jumi';
      name.length; // OK

      // 보충 undefined , any

타입 별칭

재사용하는 타입에 더 쉬운 이름을 할당하는 것

  • 파스칼 케이스로 지정 type MyName = … ;
  • 타입 별칭은 개발시에만 존재함
  • 즉, 타입 별칭은 순전히 타입스크립트의 타입 시스템에만 존재하므로 자바스크립트로 컴파일 되지 않기 때문에 런타임에서 접근 불가함
    type a = string | undefined;
    console.log(a);
    ~~~~~~~~~~~~~~~
    Error: 'a' only refers to a type, but us being used as a value here. 
  • 타입 별칭은 다른 타입 별칭을 참조할 수 있다 (순서는 상관 없음)
    type Id = number | string;
    type IdMaybe = Id | undefined | null;

1개의 댓글

comment-user-thumbnail
2023년 8월 11일

잘 읽었습니다. 좋은 정보 감사드립니다.

답글 달기