Uncaught TypeError: .then is not a function 해결 가이드 | 세상의 모든 정보

Uncaught TypeError: .then is not a function 해결 가이드

JavaScript 개발 중 'Uncaught TypeError: .then is not a function' 오류에 직면하셨나요? 이 오류는 Promise 객체가 아닌 값에 .then() 메소드를 호출하려 할 때 발생하며, 비동기 프로그래밍에서 매우 흔하게 나타나는 문제입니다. 주로 Promise 처리 방식을 잘못 이해하거나 구현했을 때 발생하는데요, 이 가이드에서는 오류의 주요 원인을 깊이 있게 분석하고, 명확한 코드 예제와 함께 효과적인 해결 방법을 상세히 알아보겠습니다.

---

1. 오류의 주요 원인 분석

.then is not a function 오류가 발생하는 가장 일반적인 시나리오들은 다음과 같습니다.

  • Promise를 반환하지 않는 함수에 .then() 사용: .then() 메소드는 오직 Promise 객체에만 사용할 수 있습니다. 함수가 Promise를 반환하지 않는데도 체이닝하려고 할 때 이 오류가 발생합니다.
  • async 함수 내에서 await 키워드 누락: async 함수는 암묵적으로 Promise를 반환합니다. 그러나 async 함수 내부에서 비동기 연산의 결과를 기다리기 위해 await 키워드를 사용하지 않으면, 해당 비동기 연산이 완료되기 전의 Promise 객체(또는 다른 값)가 반환되어 .then() 체이닝에 문제를 일으킬 수 있습니다.
  • Promise 객체가 아닌 값을 반환하는 함수 체이닝: Promise 체인의 중간 단계에서 Promise가 아닌 일반 값을 반환하는 경우, 그 다음 .then() 호출에서 오류가 발생할 수 있습니다.
  • 동기 함수를 비동기처럼 다루려는 시도: 본질적으로 동기적인 함수가 Promise를 반환할 것으로 오해하고 .then()을 붙일 때 발생합니다.
  • 라이브러리나 API의 잘못된 사용: 특정 라이브러리나 웹 API가 예상과 다른 값을 반환하거나, 비동기 처리에 대한 사용법을 잘못 적용했을 때 발생할 수 있습니다.
---

2. 효과적인 해결 방법

2.1. 함수가 Promise를 반환하는지 확인

.then()을 호출하는 함수가 실제로 Promise 객체를 반환하는지 확인하는 것이 가장 중요합니다. Promise를 반환하지 않는 함수라면, 명시적으로 Promise로 감싸서 반환해야 합니다.


// ❌ 잘못된 예 (Promise를 반환하지 않음)
function getData() {
    console.log("데이터를 가져오는 중...");
    return { status: 'success', value: 'some data' }; // 일반 객체 반환
}

// ⬇️ 오류 발생: getData()는 Promise가 아니므로 .then()을 사용할 수 없습니다.
// getData().then(result => console.log("결과:", result)); 


// ✅ 수정된 예 (Promise.resolve()로 Promise 반환)
function getPromisedData() {
    console.log("Promise 데이터를 가져오는 중...");
    // Promise.resolve()를 사용하여 일반 값을 Promise로 감쌉니다.
    return Promise.resolve({ status: 'success', value: 'some data' }); 
}

// ➡️ 정상 작동: getPromisedData()는 Promise를 반환하므로 .then()을 사용할 수 있습니다.
getPromisedData().then(result => console.log("Promise 결과:", result));
                

2.2. async/await 키워드 올바른 사용

async 함수 내에서 비동기 연산의 결과를 기다릴 때는 반드시 await 키워드를 사용해야 합니다. await을 누락하면 Promise가 완료되기 전의 상태로 넘어가서 문제가 발생할 수 있습니다.


// ❌ 잘못된 예 (await 누락)
async function fetchBadData() {
    // await이 없으면 fetch 함수가 반환하는 Promise 객체 자체가 아닌,
    // Promise 객체가 resolve되기 전의 상태(pending Promise)를 response 변수에 할당합니다.
    const response = fetch('https://jsonplaceholder.typicode.com/posts/1'); 
    // 여기서 response는 여전히 Promise 객체이므로, response.json()은 Promise의 메소드가 아님!
    // -> response.json() 대신 Promise.prototype.json()을 호출하려 시도하게 됩니다.
    const data = await response.json(); // "response.json is not a function" 오류 발생 가능
    console.log(data);
}

// ⬇️ fetchBadData().then(...)도 오류를 유발할 수 있습니다.
// fetchBadData().then(data => console.log(data)).catch(err => console.error("오류:", err));


// ✅ 수정된 예 (await 올바른 사용)
async function fetchGoodData() {
    try {
        // fetch 호출 앞에 await을 붙여 Promise가 완료될 때까지 기다립니다.
        const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
        // response는 이제 실제 Response 객체이므로 .json() 메소드를 가집니다.
        const data = await response.json(); // 여기서도 Promise를 기다림
        console.log("정상 데이터:", data);
    } catch (error) {
        console.error('데이터 가져오기 오류:', error);
    }
}

// ➡️ 정상 작동: async 함수는 항상 Promise를 반환하므로 .then()을 사용할 수 있습니다.
fetchGoodData().then(() => console.log("데이터 가져오기 완료."));
                

2.3. Promise 체이닝 로직 수정

Promise 체인에서 각 .then() 핸들러가 다음 .then()으로 전달될 Promise를 올바르게 반환하는지 확인해야 합니다. 만약 중간 핸들러가 Promise가 아닌 값을 반환하면, 다음 .then() 호출에서 오류가 발생합니다.


function step1() {
    return Promise.resolve(10); // Promise 반환
}

function step2(num) {
    console.log("Step 2:", num);
    return num * 2; // Promise가 아닌 일반 숫자 반환
}

function step3(num) {
    console.log("Step 3:", num);
    return Promise.resolve(num + 5); // Promise 반환
}

// ❌ 잘못된 Promise 체이닝 (step2가 Promise를 반환하지 않아 다음 .then()에서 오류)
step1()
    .then(result1 => step2(result1)) // step2는 Promise를 반환하지 않음
    .then(result2 => step3(result2)) // ⬇️ 여기서 'result2.then is not a function' 오류 발생!
    .then(finalResult => console.log("최종 결과 (오류 발생):", finalResult))
    .catch(error => console.error('체이닝 오류:', error));


// ✅ 수정된 Promise 체이닝 (모든 단계가 Promise를 반환하도록 수정)
function newStep2(num) {
    console.log("New Step 2:", num);
    return Promise.resolve(num * 2); // Promise.resolve()로 감싸서 Promise 반환
}

step1()
    .then(result1 => newStep2(result1)) // newStep2는 Promise를 반환
    .then(result2 => step3(result2))    // step3는 Promise를 반환
    .then(finalResult => console.log("최종 결과 (정상):", finalResult)) // -> "최종 결과 (정상): 25"
    .catch(error => console.error('체이닝 오류:', error));
                
---

3. 모범 사례 및 오류 방지 전략

비동기 코드를 작성할 때 .then is not a function 오류를 사전에 방지하기 위한 몇 가지 모범 사례입니다.

  • 함수가 Promise를 반환하는지 명확히 문서화: 함수의 JSDoc이나 주석을 통해 해당 함수가 Promise를 반환하는지, 어떤 값을 resolve하는지 명시하여 다른 개발자가 오용하지 않도록 합니다.
  • async/await와 Promise를 일관성 있게 사용: 프로젝트 내에서 비동기 처리 스타일을 통일하면 혼란을 줄이고 오류 발생 가능성을 낮출 수 있습니다.
  • 타입스크립트(TypeScript) 사용으로 타입 관련 오류 사전 방지: TypeScript는 컴파일 시점에 타입을 검사하여 Promise와 같은 타입 명시를 통해 런타임 오류를 줄여줍니다.
  • Promise.resolve()Promise.reject()로 값을 명시적으로 Promise로 감싸기: 특히 조건부 로직이나 동기적인 값을 비동기 체인에 포함시켜야 할 때 유용합니다.
  • 복잡한 비동기 로직은 async 함수로 분리: 복잡한 Promise 체인 대신 async 함수를 사용하여 가독성을 높이고 try-catch로 오류를 쉽게 관리할 수 있습니다.
---

4. 디버깅 팁

오류가 발생했을 때 문제를 효과적으로 찾아내기 위한 디버깅 팁입니다.

  1. console.log()를 사용하여 각 단계의 반환값 확인: Promise 체인의 각 .then() 블록 내부나 async 함수 내에서 console.log()를 사용하여 각 변수나 함수의 반환값이 기대하는 Promise 객체인지, 혹은 다른 값인지 확인합니다.
  2. 브라우저 개발자 도구의 네트워크 탭에서 API 응답 검사: 외부 API를 호출하는 경우, 개발자 도구의 네트워크 탭에서 실제 응답이 정상적으로 오는지, 응답 형식이 올바른지 확인합니다.
  3. Promise 체인에 .catch() 추가하여 오류 지점 파악: Promise 체인 끝에 .catch() 블록을 추가하여 오류가 발생한 지점을 특정하고, 오류 메시지를 통해 원인을 추적합니다.
  4. async/await 사용 시 try-catch 블록으로 오류 처리: async 함수 내에서 try-catch 블록을 사용하여 비동기 작업 중 발생하는 오류를 명확히 포착하고 디버깅합니다.
  5. 타입스크립트 사용 시 Promise 타입 명시로 타입 안정성 확보: 함수가 Promise를 반환할 때 Promise (예: Promise)와 같이 명시하여 개발 환경에서부터 타입 오류를 미리 발견합니다.

결론

'Uncaught TypeError: .then is not a function' 오류는 JavaScript의 비동기 프로그래밍에서 Promise 객체를 잘못 다룰 때 주로 발생합니다. 이 오류를 효과적으로 방지하고 해결하기 위해서는 Promise와 async/await의 기본 개념을 정확히 이해하고 올바르게 사용하는 것이 중요합니다.

이 가이드에서 제시한 원인 분석, 해결 방법, 모범 사례 및 디버깅 팁을 따르면 대부분의 .then is not a function 오류를 해결할 수 있습니다. 비동기 코드를 작성할 때는 항상 함수의 반환값과 타입을 신중히 고려하고, 필요한 경우 Promise.resolve()Promise.reject()를 사용하여 값을 명시적으로 Promise로 감싸는 습관을 들이는 것이 좋습니다.

이 가이드가 'Uncaught TypeError: .then is not a function' 오류를 이해하고 성공적으로 해결하는 데 도움이 되었기를 바랍니다. 추가 질문이나 의견이 있으시면 언제든지 댓글로 남겨주세요.

다음 이전

POST ADS1

POST ADS 2