본문 바로가기

프론트엔드(Front-End)/TypeScript

[TypeScript] 타입스크립트의 타입 체크 (narrowing, assertion, as)

타입스크립트와 타입 체크

타입스크립트가 단순히 타입을 지정만할 수 있다면, 참 재미 없는 언어가 되었겠죠?

타입스크립트는 개발자가 Union 등을 통해 여러 타입을 허용한 뒤 타입에 따라 분기해서 쓸 수 있는데,

이렇게 분기해서 사용할 때 한가지 문제점이 생기게 됩니다.

 

가령 위와 같이 숫자 타입의 경우 더하기(+) 연산을 하고 싶다거나, 문자열의 경우 길이 (length)를 알고 싶을 때,

유니온 타입으로 여러 타입을 허용하게 되면 타입스크립트가 컴파일 오류를 발생시키는데요.

 

왜냐하면 타입스크립트는 분명 string 또는 number 타입이 올 수 있음을 알지만, number 일때 length 프로퍼티에 접근하는 등의 잘못된 경우를 방지하기 위해 엄격히 제한하고 있기 때문입니다.

 

따라서 이런 경우에는 개발자가 타입스크립트에게 로직으로 확실하게 number라면 number 타입임을 증명해야하는데요.

 

이렇게 로직 등으로 타입이 분기되어 확실한 타입을 보장받게 하는 것,

타입을 구분하여 각 타입에 맞는 작업을 하는 것을 narrowing 한다라고 합니다.

타입스크립트의 narrowing은 아래와 같이 사용할 수 있습니다.

 

function classifier(value: string | number) {
  if (typeof value === "string") {
    console.log(`${typeof value} 입니다.`);
  } else if (typeof value === "number") {
    console.log(`${typeof value} 입니다.`);
  } else {
    console.log("never 입니다.");
  }
}

classifier("hello"); // string 입니다.
classifier(123); // number 입니다.

 

타입스크립트에서 narrowing을 할 때 사용될 수 있는 몇가지 연산자들이 존재하는데요.

대표적으로 typeof , instanceof 라는 연산자가 있으며 instanceof는 클래스 타입에서 사용할 수 있습니다.

 

이러한 연산자 외에도 어떤 속성 값을 가지는가? 와 같은 조건식으로도 narrowing이 가능하며,

아래와 같이 narrowing 할 수 있습니다.

 

// 두가지 타입이 속성명 까지 모두 같은 경우
type myCar = {
  wheel: "4개";
  color: string;
};

type myBike = {
  wheel: "2개";
  color: string;
};

function printVehicle(x: myCar | myBike) {
  if (x.wheel === "4개") {
    console.log("myCar 입니다.");
  } else if (x.wheel === "2개") {
    console.log("myBike 입니다.");
  }
}

printVehicle({ wheel: "4개", color: "red" }); // myCar 입니다.

 

타입스크립트와 AS

타입스크립트에서 as 키워드를 통해 강제로 타입을 변환시킬 수 있습니다.

하지만 as 키워드는 타입을 변환 시켜주는 것이 아니며, 단순히 타입스크립트에서 컴파일 오류를 해제시켜주는 정도의 기능만을 수행할 뿐입니다.

따라서 as 키워드는 사용을 지양하는 편이 좋으며, 개발자가 확실하게 해당 타입이 들어올 것으로 판단되는 경우에만 사용해야 합니다.

// 타입스크립트와 as
function convertType(value: string | number) {
  let newValue: number = value as number;
  let result: number = newValue + 1; // 연산 가능!
  console.log(result); // 1231
  console.log(typeof newValue); // string
}
convertType("123");

 

타입스크립트와 Assertion

타입스크립트에는 <> 기호로 타입을 선언과 동시에 정해줄 수 있습니다.

제네릭에서는 어떤 타입인지 정하는 역할을 하지만,

아래와 같이 Object 타입에서 사용한다면 type 지정을 하는 효과를 줄 수 있습니다.

이렇게 타입을 지정하는 것을 Assertion이라고 합니다.

 

// 타입스크립트와 Assertion
interface Foo {
  bar: number;
  bas: string;
}

var foo = <Foo>{
  bar: 123,
  bas: "hello",
};

console.log(foo); // { bar: 123, bas: 'hello' }