타입스크립트에서 변수에 값을 할당하고 타입을 부여하는 방법은 두 가지이다.
interface Person {name:string}
const alice:Person = {name:'Alice'}; // 타입은 Person
const bob = {name:'Bob'} as Person // 타입은 Person
이 두 가지 방법은 결과가 같아보이지만 그렇지 않다.
const alice:Person = {name:'Alice'};
방법은 타입 선언을 붙여서 그 값이 선언된 타입임을 명시한다.
const bob = {name:'Bob'} as Person
방법은 타입 단언을 수행한다. 타입스크립트가 추론한 타입이 있음에도 Person 타입으로 간주해버린다.
const bob = { } as Person
name
이라는 key 값이 없어도 강제로 타입을 지정해놨기 때문에 타입 체커에게 오류를 무시하라고 의미 하게 된다. 따라서, 타입 단언 보다는 타입 선언을 사용해야 한다.
const People=['alice', 'bob', 'jan'].map(name=>{name})
// 내가 원하는 People 의 타입은 Person[]
// 하지만 타입 추론은 People:{name:string}[]
이런 문제를 해결하기 위해
const People=['alice', 'bob', 'jan'].map(name=>{name} as Person)
으로 사용하는 것이 아니라, 아래와 같이 선언해준다.
const People=['alice', 'bob', 'jan'].map((name):Person=>{name})
// 이렇게 사용했을 때 People:Person[] 형태가 만들어질 수 있다.
타입스크립트는 DOM에 접근할 수 없기 때문에 정확한 타입 추론이 어렵다.
document.querySelector('#myButton').addEventListener('click', e=> {
e.currentTarget // 타입은 EventTarget
const button = e.currentTarget as HTMLButtonElement;
button // 타입은 HTMLButtonElement
});
우리는 #myButton 이 버튼 엘리먼트인지 알지만, 타입스크립트는 알지 못한다. 그렇기 때문에 currentTarget이 있어야 하는지 인식하지 못한다. (어떻게 선언해주어야하는지는 후반에 더 잘나오게 될 것)
특별한 문법(!)을 통해 null이 아님을 단언 할 수 있다.
보통, 변수에 const H=!true 처럼 사용하게 되면, 부정의 의미로 사용되지만 접미사로 사용하는 경우에는 일반적인 단언문이라고 생각해야한다.const el=document.getElementById('foo')!;
이럴 경우에는 null이 아니라고 확신할 수 있을 때 사용해야한다. 그렇지 않는다면 조건문을 통해 null을 체크하는 것이 좋다.
결론적으로,
타입스크립트보다 타입에 대한 정보를 잘 알고 있을 때 타입의 단언문을 사용하는 것은 괜찮다.
자바스크립트는 객체 외에도 기본 형 값들에 대한 일곱자기 타입이 있다.
기본형은 불변이며, 메서드를 가지지 않는다는 점에서 객체와 구분된다.
'primitive'.charAt(3)
하지만 , 위와 같은 예제는 메서드를 가지고 있는 것처럼 보이게 된다. string 기본형에는 없지만 String 객체 타입에는 메서드를 가지고 있기 때문이다.
자바스크립트의 동작,
string(기본형)=> String(객체)로 매핑=>메서드 호출
그러나, string 타입을 String(객체)로 사용하면 다른 타입이라고 인지하기 때문에 주의해야합니다.
타입이 명시된 변수에 객체 리터럴을 할당할 때 타입스크립트는 해당 타입의 속성이 있는지, 그 외의 속성은 없는지 확인합니다.
interface Room{
numDoors:number;
ceilingHeightFt:number;
}
const r: Room={
numDoors:1,
ceilingHeightFt:10,
elephant:'present'
// error ! Room 형식에는 알려진 속성만 지정 가능
}
객체 리터럴은 알려진 속성으로만 지정할 수 있다 !!
elephant
는 타입 Room에 없는 속성이기 때문에 에러가 발생한다.
이것은 구조적 타이핑 관점에서 안맞는다고 생각할 수 있다.
interface Room{
numDoors:number;
ceilingHeightFt:number;
}
const obj={
numDoors:1,
ceilingHeightFt:10,
elephant:'present'
}
const r: Room=obj; //정상
위와 달리 아래는 정상으로 타입 체커를 통과할 수 있다.
이와 같은 동작이 가능한 이유는 잉여 속성 체크 과정이 수행되기 때문이다. (잉여 속성 체크 과정은 객체 리터럴로 선언되지 않은 경우와 단언문으로 작성되어있는 경우 수행되지 않는다)