Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

자바스크립트 TypeError(타입 오류)란? 주요 발생 원인과 해결 방법

자바스크립트에서 TypeError는 수행할 수 없는 연산을 실행했을 때 발생하는 오류를 나타내는 객체입니다. 대개 연산에 사용된 값이 기대한 타입이 아닐 때 발생합니다.

자바스크립트의 9가지 데이터 타입

그렇다면 '타입'이란 무엇일까요? 자바스크립트 최신 표준 명세인 ECMAScript에 따르면 총 9가지 데이터 및 구조 타입이 존재합니다. 이 중 6가지(null을 포함하면 7가지)는 원시(primitive) 데이터 타입으로, string, number, bigint, boolean, undefined, symbol이 여기에 해당합니다. 연산 과정에서 TypeError가 왜 발생하는지 이해하려면 먼저 자바스크립트의 9가지 타입을 짚고 넘어갈 필요가 있습니다. 타입 분류가 확실하지 않을 때는 typeof 연산자를 활용하면 됩니다.

  1. undefined: 변수를 선언만 하고 값을 할당하지 않으면 자동으로 부여되는 값입니다. 변수에 값을 정의하는 것을 잊었을 때 흔히 'value of undefined' 형태의 TypeError가 발생합니다.
  2. Boolean: true 또는 false 두 값만 가지는 논리 데이터 타입입니다.
  3. Number: 숫자형 데이터 타입입니다.
  4. String: 백틱(`), 작은따옴표('), 또는 큰따옴표(")로 감싼 문자들의 시퀀스입니다.
  5. BigInt: 다른 프로그래밍 언어에서 bignum이라고도 불리는 임의 정밀도 숫자형 데이터 타입입니다.
  6. Symbol: Symbol 함수를 호출하여 생성되는 고유 식별자를 나타내는 값입니다.
  7. Object: 구조적(structural) 타입으로, 배열, 객체, Map, Set 등 'new' 키워드로 생성할 수 있는 거의 모든 것이 여기에 속합니다.
  8. Function: 다른 코드에서 호출할 수 있는 코드 블록으로, 데이터가 아닌 구조 타입입니다.
  9. null: 존재하지 않는 객체나 주소를 의도적으로 나타낼 때 사용하는 값입니다.

가장 흔한 자바스크립트 TypeError와 해결 방법

TypeError는 변경할 수 없는 값을 변경하려 하거나, 값을 부적절한 방식으로 사용할 때 발생합니다. 또한 함수에 전달된 인수가 함수(또는 함수 내부의 연산자)가 기대하는 타입과 호환되지 않을 때도 발생합니다.

1. 변경할 수 없는 값을 변경하려는 경우

const 키워드로 값을 할당하면 그 값은 상수(constant)가 되어 더 이상 변경할 수 없습니다. 상수 변수의 값을 변경하려고 시도하면 TypeError가 발생합니다.

const a = 5
a = "5"
// Uncaught TypeError: Assignment to constant variable.

이 문제는 문자열 "5"를 담을 새로운 식별자 이름을 선언하는 것만으로 간단히 해결할 수 있습니다.

const a = 5
const b = "5"

2. 값을 부적절한 방식으로 사용하는 경우

개발자는 값이 의도된 용도대로 사용되고 있는지 반드시 확인해야 합니다. 아래 예제에서는 garfield가 Cat() 함수의 인스턴스인지 검증하려는 과정에서 'Cat'과 'garfield'의 위치가 서로 바뀌어 있습니다.

function Cat() {}
function Dog() {}

let garfield = new Cat()

Cat instanceof garfield

// Uncaught TypeError: Right-hand side of 'instanceof' is not callable

두 항목의 순서를 올바르게 바꾸면 해결됩니다.

function Cat() {}
function Dog() {}

let garfield = new Cat()

garfield instanceof Cat

3. 함수가 기대하는 타입과 호환되지 않는 인수를 전달하는 경우

연산을 작성할 때 개발자는 원하는 결과를 얻을 수 있는 방식으로 값을 사용해야 합니다. null은 객체의 부재를 의도적으로 나타내는 데 유용하지만, 아래 예제처럼 함수가 기대하는 타입과 호환되지 않는 인수로 전달하면 TypeError가 발생합니다.

function readingErrorsAreImportant(a){
    if(a.length === 5){
      return "equals five"
    } else if(a.length > 5) {
      return "Greater than five"
    } else {
      return "Less than five"
    }
}
console.log(readingErrorsAreImportant(null))

// Uncaught TypeError: Cannot read property 'length' of null

함수가 기대하는 값 타입, 예를 들어 숫자 타입을 전달하면 오류를 해결할 수 있습니다.

function readingErrorsAreImportant(a){
    if(a.length === 5){
      return "equals five"
    } else if(a.length > 5) {
      return "Greater than five"
    } else {
      return "Less than five"
    }
}
console.log(readingErrorsAreImportant(10))

결론

코드에서 TypeError가 발생하는 이유를 정확히 이해하는 것은 효과적인 디버깅의 첫걸음입니다. 타입 분류가 확실하지 않을 때는 typeof 연산자를 사용하면 9가지 데이터 또는 구조 타입 중 하나를 반환해 주므로, 이를 통해 어떤 방향으로 디버깅을 진행해야 할지 더 명확하게 파악할 수 있습니다.