Javascript와 달리 Typescript는 type을 지정할 수 있다.
export interface ReviewDTO {
id: number;
rating: number;
content: string;
movie_id: number;
nickname: string;
is_liked: boolean;
likes_count: number;
comments_count: number;
}
하지만 위에서 설정한 type만을 믿고 안전하다 생각하며 사용해선 안된다.
실행시점에는 지정된 것과 다른 type의 데이터가 들어올 수 있기 때문이다.
TypeScript로 작성된 코드는 Javascript로 변환된 후 실행되기 때문이다.
즉, 컴파일 시점 까지의 type 안전성만 보존하며, 실행시점에서의 type을 명확히 보장하진 않는다.
가령 서버로 부터 전송되는 데이터의 타입은 런타임중에 결정되므로, 이때의 타입까지 보장해주진 못한다.
특히, 백엔드가 DB에서 가져온 데이터를 그대로 DTO에 담아 프론트로 전송할때, type이 보장되지 않는 사고가 발생하기 쉽다.
가령TypeOMR는 Count(*) 또는 COALESCE(...)로 만들어진 값들은 직관적으로 정수라고 생각하기 쉬운데, 실은 SQL 문자열(string)으로 처리되는 경우가 많다.
'COALESCE(like_summary.like_count, 0) AS likes_count',
'COALESCE(comment_summary.comment_count, 0) AS comments_count',
만일 해당 명령로 얻은 값을 파싱하지 않고 그대로 넘겨준다면, DTO에서 정의한것과 다른 타입의 데이터가 들어가게 되는 셈이다.
CAST(COALESCE(like_summary.like_count, 0) AS UNSIGNED) AS likes_count
하지만 위 방법은 DBMS의 종류에 따라 결과값을 보장하지 못한다는 단점이 있다.
class ReviewDto {
likes_count: number;
comments_count: number;
static fromRaw(raw: any): ReviewDto {
return {
...raw,
likes_count: Number(raw.likes_count),
comments_count: Number(raw.comments_count),
};
}
}
다소 번거롭더라도 위와 같은 방법을 쓰는것이 안전하다.
Typescript에서 Type을 보장하는것은 컴파일 단계 까지이며, 런타임에는 Javascript와 마찬가지로 Type을 보장하지 않는다.
DB나 외부 저장소 및 서비스 등에서 읽어온 데이터는 수신측에서도 type이 일치하는지 재차 검토해야한다