TypeScript의 자료형 및 타입 표명

TypeScript로 작성된 코드는 코드가 실행되기 전 Compile Time에 타입을 강제합니다. 여기서 중요하게 봐야할 부분은 컴파일 시간에 타입을 강제한다는 점입니다. 런타임 시에는 실제로는 외부에서 들어오는 데이터나 Parse된 JSON과 같이 동적으로 입력되는 데이터는 타입에 대해 Cast하거나 오류를 발생시키지 않습니다. 즉 타입스크립트의 타입 표명은 런타임의 Type Casting이 아니라는 점을 꼭 상기해야합니다. 타입 표명은 컴파일 시간을 위한 것이고 어떤식으로 분석되길 원하는지 컴파일러에게 제공하는 힌트일 뿐입니다.

런타임에 타입 체크가 필요한 이유

앞서 말했듯이 타입스크립트는 런타임에서 동적 데이터의 자료형을 보장하지는 않습니다. 예를 들면 아래의 간단한 경우들을 살펴보도록 하겠습니다.

  1. Front-End에서 잘못된 타입으로 API 호출하는 경우
  2. API가 잘못된 타입으로 반환하는 경우

1번과 2번 모두 내가 정의한 타입 그대로 지켜질지 아닐지 모르는 런타임에 외부에서 들어오는 데이터인 경우입니다.

이처럼 늘 휴먼에러가 발생할 수 있다는 점을 가정하고 안전한 코드를 작성해야 합니다.
따라서 런타임에도 타입스크립트가 자료형을 지켜줄 것이라고 믿거나 휴먼 에러가 발생하지 않을 것이라고 믿는 것은 어리석은 행동이다. 이경우 자바스크립트의 특성상 치명적인 오류를 초례할 가능성이 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
interface ExpectedUserInput {
message: string;
}

class EchoController extends Controller {
public echo(req: Request, res: Response) {
const body = req.body as ExpectedUserInput;

console.log(typeof body.message, body);
res.json({ yourMessage: body.message });
}
}

위처럼 간단한 Echo API를 살펴보겠습니다. body.message의 자료형은 string으로 보장될 것이라 예상할 수 있습니다.

API Request Body

1
2
3
{
"message": 0
}

하지만 string일 것이라는 예상과 달리 실제 호출시 입력한 값의 자료형으로 그대로 들어가게 됩니다.

Console Result

1
number { message: 0 }

타입스크립트의 장점만을 바라고 이부분을 놓친채로 사용한다면 실제 타입스크립트의 장점을 온전히 누리지 못한 채로 생산성만 낮추며 두마리 토끼를 다 잃을 수 있다고 생각합니다.
적절한 Type Guard 없이 타입을 정의해 사용한다면 오히려 개발자들에게 있어 해당 데이터의 타입의 혼란과 실수만을 야기할 수도 있습니다.
따라서 컴파일 시간에 데이터의 타입을 특정할 수 없는 경우 TypeGuard를 통해 타입스크립트의 장점을 온전히 가져야 하지 않을까 싶습니다.

TypeGuard

따라서 런타임시에 typeof 혹은 instanceof 등의 적절한 Type Guard로 타입을 보장해야합니다. 타입 가드에 대한 내용과 라이브러리들은 다음 포스트에서 조금 더 자세히 다루도록 하겠습니다.