이펙티브 타입스크립트 (댄 밴더캄 지음) 를 읽고 정리
📍타입을 부여하는 2가지 방법
1️⃣ 타입 선언 (Declaration) : 일반적인 방법 (: type)
2️⃣ 타입 단언 (Assertion) : as 키워드를 사용하여 타입을 강제로 지정하고, 타입 체커에게 오류를 무시하게 함
- 예시
interface Person {
name: string
}
const alice: Person = { name: "Alice" }; // 타입 선언
const bob = { name: "Bob" } as Person; // 타입 단언
⭐ 타입 선언을 사용하는 것이 좋다!
- 이유 : 타입 단언은 타입 체크를 무력화한다
interface Person {
name: string
}
const steve: Person = {}; // 에러 -> name 프로퍼티가 Person에 있어야 하지만 없음
const michael = {} as Person; // 정상 -> 타입 체크 없이 타입 단언
const john: Person = {
name: "John",
occupation: "developer" // 에러 -> Person 타입에 occupation 프로퍼티 없음
}
const ryan = {
name: "Ryan",
occupation: "manager"
} as Person // 에러 없음
📍타입 단언의 2가지 방법
1️⃣as 키워드 ✅
2️⃣<> : 리액트의 tsx 에서 컴포넌트 태그로 인식되어 잘 안 씀
📍 화살표 함수 내부에서 타입 선언하기
- 괄호를 신경쓰지 않으면 뜻밖의 에러를 맞을 수 있다
- 예시
// 아래 코드에서 people 에 Person[] 타입을 부여하려면?
const people = ["alice", "bob", "jan"]
const test = people.map(name => {name}); // 현재는 void[] 타입
// 1st try : 타입 단언
const test1 = people.map(
name => ({name} as Person)
); // Person[] 타입
// 하지만, 엄밀하게 맞는 방법이 아님 -> {name} 대신 {}를 써도 에러 x
// 2nd try : 타입 선언
const test2 = people.map(name => {
const person: Person = {name};
return person
}); // Person[] 타입
// 코드를 더 간결하게 줄일 수 없을까??
// 3rd try : 타입 선언
const test3 = people.map(
// name에 괄호가 없으면 에러
// name: Person => {name} // 에러 -> name이 Person 타입이고 반환 타입이 없음
// (name: Person) => ({name}) // 에러 -> name이 Person 타입이고 반환 타입이 없음
(name): Person => ({name}) // 반환 값이 Person 타입
);
- name: Person 은 콜백함수의 인수인 name에 Person을 부여하려고 하기 때문에 에러가 발생한다
대신, 콜백 함수의 반환값에 Person을 부여해야 한다
📍타입 단언이 꼭 필요할 때
- DOM element에 접근할 때는 타입 단언이 필요하다
- 타입스크립트가 DOM에 접근할 수 없기 때문에 DOM element가 없을 수도 있다고 여겨버린다
- 예시
// #mybutton이 null 일 수 있어서 에러 발생하기 때문에 !를 붙여 null 타입이 아님을 단언
// !을 접미사로 쓰면, null의 부정
document.querySelector("#mybutton")!.addEventListener("click", e => {
e.currentTarget; // EventTarget 타입
const button = e.currentTarget as HTMLButtonElement;
button; // HTMLButtonElement 타입
})
- 따라서 DOM에 접근할 때는, ! 또는 as를 통해 엘리먼트가 null 타입이 아님을 단언해야 한다