Today
-
Total
-
  • TypeScript로 React를 사용하면 왜 import 구문이 다를까요?
    Coding/React.js 2020. 10. 12. 22:45

     

    최근에 리액트를 TypeScript에서 많이 사용하게 되면서, 이 쪽으로 유저들의 개발이 많이 이루어지고 있습니다.

     

    실제로 TypeScript 커뮤니티 중 하나인
    definitelytyped.org

    를 방문해 보면, 유명한 라이브러리들은 이미 유저들이 .d.ts 파일을 만들어 놓은 경우가 많습니다.

     

     

    (실제로 타입스크립트를 사용해 프로젝트를 꾸리실 때 이 사이트를 애용하는 것을 추천합니다. npm 모듈 중 아주 유명한 모듈을 제외하면 @types 형태를 제공하지 않고 있고, 타입스크립트를 위해 만들어야하는 .d.ts 파일들을 이 사이트에서 많이 받을 수 있거든요!)

     

     

    하지만 아주 유명하고 대중적인 라이브러리 중 하나인 react, react-dom은 이미 @types/의 형태로 npm/yarn에서 다운로드 할 수 있습니다. 특히 TypeScript에서 react는 @types/react라는 것을 추가로 설치해주면, JS에서 사용하는 것과 거의 동일하게 사용할 수 있습니다. 그런데 이렇게 설치했을 때 차이가 있습니다. 우선 JavaScript와 TypeScript에서의 react의 import 구문을 각각 볼까요?

     

     

    javascript

    import React from 'react';
    import ReactDOM from 'react-dom';

    typescript

    import * as React from 'react';
    import * as ReactDom from 'react-dom';

     

    같은 곳에서 가져오는데, 받아오는 형식이 다릅니다. 그 이유는 뭘까요? 우선 TS에서 react 위에 커서를 올리고, Go to the Definition(정의로 이동)을 클릭해 봅시다.

     

    React가 export default가 아닌 namespace의 형태로 export되고 있습니다. 그렇기 때문에 import React from 'react' 형태로는 불러올 수가 없습니다. default export가 없으니 어떤 것을 기본으로 받아와야 하는 지 모르기 때문에 오류가 뜨는 것이죠. 그렇기 때문에 namespace 형태로부터 받아오기 위해 * as React라고 사용하는 것입니다.

     


     

    엥?? 🤔
    TS에서도 이렇게 사용하기도 하는데요?
    import React from 'react';
    import ReactDOM from 'react-dom';

     

    맞습니다. 타입스크립트에서도 다음과 같은 형태로 받아올 수가 있습니다. 왜 말을 바꾸시죠

     

    하지만 저렇게 사용해 보면 처음에는 다음과 같이 에러가 뜹니다.

    이를 이해하기 위해 다음과 같이 수정해 봅시다.

    이건 또 된다(?)

    commonJS 모듈을 받아오는 키워드인 require를 사용하면 에러가 발생하지 않습니다. ES6 문법인 import 구문을 사용할 때는 에러가 발생합니다. 에러를 한번 확인해 봅시다.

     

     

    esModuleInterop 플래그를 사용하는 경우에만 기본 가져오기와 함께 사용할 수 있다고 합니다. 여기서 esModuleInterop은 commonJs 모듈을 ES6사양에 준수하여 받아올 수 있게 해줍니다. 즉, 이 플래그를 키면 자동으로 다음과 같이 변환하여 받아온다는 얘기입니다.

     

    // Before
    import React from 'react';
    
    // After
    const React = __importDefault(require('react'));
    

     

    이해가 가시나요? 이 플래그는 tsconfig.json에서 킬 수 있습니다. 다음과 같이 작성해 봅시다.

     

    tsconfig.json

    {
        "compilerOptions": {
            ...
            "esModuleInterop": true
        },
    
    }

     

    이제 다시 확인해보면 에러 없이 정상적으로 import 됩니다. 하지만 인프런에서 '웹 게임을 만들며 배우는 React에 TypeScript 적용하기' 강의를 진행중이신 ZeroCho님에 따르면, '모듈이라는 것의 특성을 이해하지 못한 상태에서 무작정 저 플래그를 켜서 해결하는 것은 좋지 못하다'고 하면서, 보기에 불편할 수 있지만 import * as React from 'react' 를 사용하는 것을 권장하셨습니다. 

     

    각자 취향(?)에 맞게 사용하면 될 것 같습니다. 궁금증이 해결되었으면 좋겠네요!

    댓글