# 타입스크립트 타입 추론 / 단언 / 가드
# 타입 추론
타입스크립트가 해당 코드를 판단하는 기준에 대해 알아봅니다.
# 기본
타입스크립트는 코드에서 변수를 선언하거나, 할당 할때 추론이 일어납니다.
let x = 3; // 선언함으로 x는 number라는 추론 일어남
또는 함수를 선언하고, 파라미터에 기본값을 넣으면 추론 일어납니다.
// 파라미터에 기본값을 선언함으로 b는 number라는 추론이 일어남
function test(b = 10) {
return b;
}
# 인터페이스 추론
interface DropDown<T> {
value: T;
title: string;
}
interface DetailedDropDown<K> extends DropDown<K> {
des: string;
tag: K;
/** extends에 의해 아래 타입이 추가됨
* value: K, title: string
* */
}
// 인터페이스의 제네릭의 값에 따라 정의된 타입이 론되는 상황
let shoppingItem: DropDown<string> = { value: "test", title: "test2" };
let detailedItem: DetailedDropDown<string> = {
value: "test3",
title: "test4",
des: "test5",
tag: "test6"
};
# best common type 추론 방식
배열 안에 여러 타입이 정의된 경우 추론은 유니온 타입으로 정의됩니다
const arr = [1, 2, true, "string"]; // (number | boolean | string)[]
# 타입 단언 (type assertion)
타입스크립트에서 추론하는 값보다 개발자가 해당 변수의 타입을 더 잘 알고있을때, 변수에 원하는 타입을 강제로 부여합니다.
let a;
a = "20";
a = 10;
let b = a;
// ts에서 a는 any로 추론하기 때문에 b도 any라고 ts는 추론한다.
// 그러나 개발자는 b가 10
// 즉, number임을 알기 때문에 b에 number를 강제로 assertion 한다
let b = a as string;
DOM Api를 조작할 때, 가장 많이 사용합니다. (querySelector, getElementById 등등)
let div = document.querySelector(".container");
div.innerText = "..."; // error: Object is possibly null.
위처럼 정의하면 div는 container이라는 class가 없을 수 있기 때문이다. HTMLDivElement | null
이라는 타입을 보장받습니다. 타입 단언을 모른다면 null을 타입 가드 시켜주기 위해 아래와 같이 코드를 짭니다.
let div = document.querySelector(".container");
if (div) {
div.innerText = "...";
}
만약 container이라는 class가 코드가 실행되는 시점에 무조건 존재한다라고 개발자가 확신한다면 type assertion을 이용하여 타입 가드를 제거하고 타입 단언으로 null 값을 제거합니다.
let div = document.querySelector(".container") as HTMLDivElement;
div.innerText = "...";
# 타입 가드 (type guard)
함수의 파라미터로 유니온 타입이 지정되는 경우 타입이 2개 이상임으로 공통되는 속성만 사용이 가능합니다. 이럴 경우 각 타입을 분기 처리하여 타입별로 로직을 분리 하기 위한 작업입니다.
interface Dev {
name: string;
skill: string;
}
interface Person {
name: string;
age: number;
}
function introduce(): Dev | Person {
return { name: "d", age: 33, skill: "c" };
}
const tony = introduce(); // Dev | Person 으로 공통된 속성만 사용가능. 즉, tony.skill 불가
// skill을 빼고 싶다면? -> type assertion으로 사용 가능
if ((tony as Dev).skill) {
console.log((tony as Dev).skill);
} else if ((tony as Person).age) {
console.log((tony as Person).age);
}
// 너무 assertion을 많이 씀으로 타입 가드 함수를 만든다.
// 타입 가드 정의
// target is Dev -> 넘겨 받은 파라미터가 해당 타입인지를 확인
function isDev(target: Dev | Person): target is Dev {
// skill이 있다면 Dev이다
return (target as Dev).skill !== undefined;
}
if (isDev(tony)) {
// name, skill 사용 가능
console.log(tony.skill);
} else {
// name, age 사용 가능
console.log(tony.age);
}