- 타입 단언(type assertion)은 타입스크립트의 타입 추론에 기대지 않고 개발자가 직접 타입을 명시하여 해당 타입으로 강제하는 것을 의미함.
- 변수에 초깃값을 설정했으므로 string으로 타입을 추론함. 근데 as 키워드를 통해 타입을 정해줄 수 있다.
let myName = "현준" as string
interface Person {
name: string
age: number
}
var ha = {}
ha.name = "현준"
ha.age = 22
- 이렇게 사용하면 에러가 발생한다. 이유는 ha를 빈 객체로 선언했기 때문에 컴파일러는 어떤 값이 들어갈지 모르기 때문이다.
var ha = {} as Person
ha.name = "현준"
ha.age = 22
- 이때 as 키워드를 통해 객체에 들어갈 속성을 미리 정의하는 것이다.
- 타입 단언은 숫자, 문자열, 객체 등 원시값 뿐만 아니라 변수나 함수의 호출 결과에도 사용이 가능하다.
function getId(id) {
return id
}
let myId = getId("josh") as number
- 함수의 결과값을 number로 타입단언하여 사용할 수 있다.
- 타입 단언은 여러번 중첩해서 사용도 가능하다.
let num = 10 as any as number
- 위 코드는 타입 단언을 여러번 중첩해서 사용이 가능하다는 것을 보여주기 위한 예시이며 위는 타입추론이 되기 때문에 굳이 타입 단언을 할 필요가 없는 코드이다.
- as 키워드는 구문 오른쪽에서만 사용한다 타입 단언은 변수 이름에 사용할 수 없다.
- 이럴떈 타입 표기로 타입을 정하는게 올바른 방법이다 . 호환되지 않는 데이터 타입으로는 단언할 수 없다.
- 타입 단언을 사용하면 원하는 타입으로 단언할 수 있을 것 같지만 실제로는 그렇게 하지 못하다.
- number인 10을 string으로 변환할 수 없기에 타입 에러가 발생한다.
- 타입 단언은 코드를 실행하는 시점에서 아무런 역할도 하지 않기 때문에 에러에 취약한 측면이 있다. 타입 에러를 쉽게 해결하려고 타입을 단언해서 타입에러는 해결하지만 실행했을때는 에러를 방지 못할 경우가 생긴다.
interface Profile {
name: string;
id: string;
}
function getProfile() {
...
}
let myProfile = getProfile() as Profile;
renderId(myProfile.id);
- getProfile이라는 함수가 타입을 정의하기 복잡해 as를 사용해 타입을 단언하고 myProfile을 넘기는 함수 예시이다. renderId에 id를 넘길떄 단언을 했기 때문에 타입에러는 나지 않는다. 그러나 실행했을 때 오류가 발생할 수 있다.
- 예를 들어 getProfile에서 받아온 값이 undefined인 경우 id가 없기 때문에 런타임 에러가 발생한다. myProfile 자체가 undefined이니 undefined.id는 당연히 오류가 발생하는 것이다.
- !는 null 아님 보장 연산자(non null assertion)은 null 타입을 체크할 때 유용하게 쓰는 연산자이다.
function shuffleBooks(books) {
let result = books.shuffle();
return result;
}
- 다음 함수를 실행하면 book을 랜덤하게 섞는 함수이다. 이때 books가 없다면 shuffle메소드가 실행되지 않기 때문에 오류를 발생시킬 것이다.
- 이런 상황을 방지하기 위해 null 값 체크가 필요하다.
function shuffleBooks(books: Books || null) {
if(books ==== null || books === undefined) return;
let result = books.shuffle()
return result
}
function shuffleBooks(books: Books || null) {
let result = books!.shuffle()
return result
}
- 이때 books가 null이 아니라는 확신이 있으면 ! 연산자를 사용하여 타입에러를 없애줄 수 있다. 그러나 위 코드에서는 null이 들어올 가능성이 있기 때문에 위의 코드처럼 if문으로 방어해주는게 올바른 방법이다.
let divElement = document.querySelector("div") // HTMLDivElement | null
// if(divElement) divElement.addEventListener("click", clickHandler)
divElement!.addEventListener("click", clickHandler)
- divElements는 null일 수 있기 때문에 if문으로 감싸야 타입에러를 없앨 수 있는데 div태그가 무조건 있는게 확신이 들면 !로 간편하게 쓸 수 있다. 그래도 가급적 타입 단언보다는 타입 추론에 의지하는 것이 좋다.