[TypeScript에서 DOM 다루기] - HTMLElement타입은 만능이 아닙니다

조민호·2023년 10월 27일
0
post-custom-banner

HTMLElement 은 모든 HTML요소 타입의 최상위 타입이다

그래서 언뜻 보면 , input 태그의 경우 HTMLElement 를 사용하지 않고

굳이 HTMLInputElement로 타입을 구분지어서 사용할 필요가 있나 싶기도 했다

그렇지만 반드시 구분을 지어야 하며 차이가 존재한다

getElementById()로 HTML태그를 불러올 때 리턴받는 DOM객체의 타입은 HTMLElement이다


// lib.dom.d.ts


/**
* Returns a reference to the first object with the specified value of the ID attribute.
* @param elementId String that specifies the ID value.
*/
getElementById(elementId: string): HTMLElement | null;

HTMLElement타입은 DOM객체의 기본타입이고

HTMLInputElement 같은 타입들은 HTMLElement타입을 상속한다

그리고 이때 , input태그의 값에 접근할 수 있는 **.value속성을 예로들면**

  • HTMLElement에는 존재하지 않지만
  • HTMLInputElement에만 존재한다 HTMLInputElement가 상속을 하면서 추가된 것이다

그러므로 TS에서는 input태그에 대해 .value 속성을 사용하기 위해선
타입을 HTMLElement 대신 , HTMLInputElement로 해야 합니다

// HTML
<input type="text" id="username" placeholder="Enter username" />

// TS
// Non-null Assertion 필수
const username:HTMLElement = document.getElementById('username')!;
console.log((username as HTMLInputElement).value) // 해당 input태그의 내용이 출력
  • 위의 코드를 보면, getElementById는 null값이 리턴될 수 있으므로 non-null assertion을 사용해 줍니다
  • 또한 username이라는 id를 가진 DOM객체를 받아올 때 이게 무슨 요소인지 확신할 수 없으므로 이걸 받는 변수에게 HTMLElement타입을 지정해 주고 , 사용할때 HTMLInputElement로 type assertion을 사용합니다
💡 그렇지만 보다 간결하게 초반부터 바로 HTMLInputElement로 type assertion을 사용할 수도 있습니다

이렇게 하면 null값도 자동으로 방어가 되고 , 바로 .value속성을 사용할 수 있으므로 보다 코드가 간결해 집니다

// HTML
<input type="text" id="username" placeholder="Enter username" />

// TS
const username:HTMLInputElement= document.getElementById('username') as HTMLInputElement;
console.log(username.value) // 해당 input태그의 내용이 출력

getElementById() 같은 메소드로 DOM요소를 불러올때 null값을 막아줘야 하는데 굳이 non-null assertion이나 다른 방법으로 null을 막기보다는 , type assertion을 통해 바로 막을 수 있습니다


TS에서 실제로 사용해보기

// username은 HTMLElement
const username = document.getElementById('username') as HTMLElement;

// checkLength의 인자로 username을 넘겨줌
checkLength(username); // 에러 발생

// checkLength의 인자는 HTMLInputElement 타입
function checkLength(input:HTMLInputElement) { ... }

처음에는 HTMLElement가 가장 상위 개념이므로 HTMLInputElement
타입에도 사용이 가능할 줄 알았다

그렇지만 위의 방법처럼 HTMLInputElement 에다가 HTMLElement를 사용하게 될 경우 아래와 같은 에러가 발생한다

'HTMLElement' 형식의 인수는 'HTMLInputElement' 형식의 매개 변수에 할당될 수 없습니다.

'HTMLElement' 형식에 'HTMLInputElement' 형식의 accept, align, alt, autocomplete 외 53개 속성이 없습니다.

이를 해결 하는 방법은 2가지가 있다

  1. HTMLElement타입의 요소에다가 type assertion을 사용

    // username은 HTMLElement
    const username = document.getElementById('username') as HTMLElement;
    
    // checkLength의 인자로 username을 넘겨줌
    checkLength(username **as HTMLInputElement**);
    
    // checkLength의 인자는 HTMLInputElement 타입
    function checkLength(input:HTMLInputElement) { ... }
    // username은 HTMLElement
    const username = document.getElementById('username') as HTMLElement;
    
    // checkLength의 인자로 username을 넘겨줌
    checkLength(username); 
    
    // checkLength의 인자는 HTMLElement 타입
    function checkLength(input:**HTMLElement**) { 
    
    	// 사용하게 될 때 type assertion을 해서 사
    	(input **as HTMLInputElement**)
     }
  1. 아예 처음에 DOM객체를 가져올때부터 type assertion으로 HTMLInputElement으로 선언해주기

    // username은 **HTMLInputElement 타입**
    const username = document.getElementById('username') **as HTMLInputElement;**
    
    // checkLength의 인자로 username을 넘겨줌
    checkLength(username); 
    
    // checkLength의 인자는 HTMLInputElement 타입
    function checkLength(input:HTMLInputElement) {...}
post-custom-banner

0개의 댓글