TypeScript - Narrowing, Assertion

Boo Sung Jun·2022년 3월 16일
0

TypeScript

목록 보기
3/8
post-thumbnail

Narrowing

함수에서 연산을 하거나 string의 length를 사용할 때에는 narrowing 통한 타입 체크를 해줘야 한다. 타입스크립트에서 사칙연산은 number type만 가능하다. union type에 number 타입이 있거나 unknown 타입이어도 불가능하다. 또한 number 타입으로 선언된 다른 변수에 union type이나 union type도 할당이 불가능하다.

1. typeof

if문에서 typeof 변수 를 이용하여 변수가 어떤 타입인지 체크한 뒤, 연산을 수행한다.

function 함수(x: number | string) {
    // typeof 외에 in, instanceof 도 narrowing으로 사용 가능
    if (typeof x === "number") {
      // 연산
      console.log(x + 1);
      // number type 배열에 할당 
      let array: number[] = [];
      array.push(x);
    } else {
      // narrowing 할 때 else 꼭 넣어줘야 에러 안생김
      console.log("x is string");
    }
}

타입이 array인지 체크할 때에는 typeof 대신 Array.isArray()를 사용할 수 있다.


// 전달 받은 과목 속성의 타입이 string이면 그냥 리턴하고,
// 배열이면 마지막 원소를 리턴한다.
function homework(obj: { subject: string | string[] }): string {
  if (typeof obj.subject === "string") {
    return obj.subject;
  } else if (Array.isArray(x.subject)){
    return obj.subject[obj.subject.length - 1];
  } else {
    return 'no subject'
  }
}

console.log(Homework({ subject: "math" }));  // 출력: math
console.log(Homework({ subject: ["science", "english"] }));  // 출력: english



2. in 키워드

커스텀 타입을 narrowing하려면 in을 사용해야 한다.
아래와 같이 커스텀 타입을 사용하는 경우 typeof를 쓸 수 없다. typeof 연산자는 number, string, boolean, object등 기본 타입에만 사용 가능하다.

  type Cat = { 야옹: string };
  type Dog = { 멍멍: string };

  function 함수(animal: Cat | Dog) {
    // 에러 발생
    if (typeof animal === 'Cat') {
      animal.야옹;
    }
    
	// 정상 작동
    if ("야옹" in animal) {
      animal.야옹;
    }
  }



3. instanceof

class로 생성된 instance인 경우, instanceof로 narrowing할 수 있다.

  let 날짜 = new Date();
  if (날짜 instanceof Date) {
  }

날짜에서 instanceof가 많이 사용된다.



4. &&을 이용한 undefined, null 체크

undefined 체크할 때, &&을 사용하면 undefined를 체크하기 위한 if문을 줄일 수 있다.

  function 함수(a: string | undefined) {
    // a가 undefined면 실행 안됨
    // string이면 실행
    if (a && typeof a === "string") {
      console.log("a is string");
    }
  }

undefined 외에 null도 사용 가능하다.
그리고 조건식을 if (변수 != null) 이렇게 써도 null, undefined 이거 두 개를 동시에 거를 수 있다.

&& 설명

  • 조건식 2개가 참이면 전부 참으로 판정해주는 논리연산자
  • true/false 대신 자료형은 넣으면 && 사이에서 처음 등장하는 falsy 값을 찾아주고 그게 아니면 마지막 값을 남긴다.
  • falsy: false와 유사한 기능하는 타입들(null, undefined, NaN)
	1 && 2 && 3 -> 3
	1 && 2 && undefined && 3 -> undefined



5. literal type을 이용한 narrowing

비슷한 오브젝트 타입들을 만들어 사용하는 경우, 오브젝트 타입마다 literal type을 만들어두면 narrowing이 편리해진다.

 type Cat = {
    crying: "야옹";
    name: string;
  };
  type Dog = {
    crying: "멍멍";
    name: string;
  };

  function 함수(x: Cat | Dog) {
    if (x.crying === "야옹") {
      console.log("강아지 이름: " + x.name);
    } else {
      console.log("고양이 이름: " + x.name);
    }
  }

CatDog 오브젝트의 속성이 모두 같지만, crying 속성을 literal type으로 지정하여 unique하게 구분 가능하다. object들 구분할 일이 많을 때, 이렇게 literal type을 만들어두면 편리하다.


Assertion

as를 이용하여 타입을 덮어쓰는 방법이다.

let array: number[] = [];
    array[0] = x as number;

단, 아래처럼 이미 할당된 변수의 타입 변경은 안된다.

 let 이름: string = "kim";
 이름 as number;  // 에러

아무때나 사용하면 안되고, 무슨 타입이 들어올지 확실할 때에만 assertion 사용해야 한다. 주로 에러 디버깅 할 때 잠깐 사용한다.

0개의 댓글