2022-01-20 18:09 작성

2022-01-21 10:36 수정

d.ts에서의 명시적 Module import에 관해

Table of contents

도입

// can not find module
import example from 'assets/Tiger.png';

Cannot find module 'assets/protein.png' or its corresponding type declarations.

// tsconfig
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
        "app/*": ["./src/app/*"],
        "config/*": ["./src/app/_config/*"],
        "environment/*": ["./src/environments/*"],
        "shared/*": ["./src/app/_shared/*"],
        "helpers/*": ["./src/helpers/*"],
        "tests/*": ["./src/tests/*"],
        "assets/*": ["./assets/*"],
    },
  }
}

위와 같이 tsconfig.json이 설정 되어 있다고 해도 assets 폴더의 png, jpeg 등의 resources를 import 할 때 에러가 발생할 수 있다. 이 문제를 해결하기 위해 다음의 두 가지 사례를 기술해둔다.

실패 사례

// tsconfig
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
        "app/*": ["./src/app/*"],
        "config/*": ["./src/app/_config/*"],
        "environment/*": ["./src/environments/*"],
        "shared/*": ["./src/app/_shared/*"],
        "helpers/*": ["./src/helpers/*"],
        "tests/*": ["./src/tests/*"],
        "assets/*": ["./assets/*"],
    },
  },
  // Test 1
  "include": ["assets/*"],
  // Test 2
  "include": ["**/*.png"],
}

TypeScript의 Include를 이용해 TypeScript가 적용되는 범위를 지정해도 제대로 적용되지 않았고 똑같은 에러 메시지가 출력 되었다.

성공 사례

// d.ts
declare module 'assets/*.png' {
  const value: any;
  export = value;
}

Stackoverflow - declare module에서 d.ts에서 직접 Modul을 선언하는 방법을 제시했고 위와 같이 문구를 집어넣었다. 그 결과 TypeScript에서 찾지 못하던 Reference error가 해결 되었다.

고찰

그러나 이 부분은 정확히 말해 해결이라고 볼 수는 없을 것이다. d.ts에서 선언된 이 부분은 assets/*.png에 대해서 ‘내가 해당 파일들이 있음을 보장’하며, 해당 File들은 어떤 Type을 가져야 함을 기술하는 것이기 때문이다. 그렇기에 fallback을 적용하는데 있어 다음의 두 가지가 선행 되어야 한다.

  1. babel.config.js File이 있는 경우 pluginsmodule-resolver, 그 안의 rootalias 부분이 실제적으로 적용되어 build 할 때에도 reference check가 확실해야만 한다.

  2. tsconfig.json에서 babel.config.js와 동일한 relative path에 대한 reference check가 존재해야 한다.

위의 두 가지가 제대로 적용됐음에도 module error가 발생할 때에만 fallback을 사용할 때 기대하는 Performance가 나올 것이다. 만약 위의 두 가지가 선행되지 않으면 type check는 문제없는데 build 에러가 나게 되므로 유의한다(Bug가 확인 되지 않으므로 찾는데 시간을 허비할 수 있다는 의미).

또한, 상기의 declare module은 사용하는 Library나 기존 components의 hard한 type 지정 및 타입 에러 수정에 응용 될 수 있다. 다음은 react-navigation에서 navigate Method type이 존재하지 않아 발생하는 Type error를 수정하는 방법이다.

아래의 방법을 통해 매번 useNavigation<StackNavigationProp<any>>() 할 수고를 덜 수 있게 된다.

Advanced 시행착오1

// 최상위 디렉토리의 parent.d.ts
// navigate type error가 발생했을 때 수정 방안

import '@react-navigation/native';
import { useNavigation } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';

// declare const 형태의 type이 있을 경우 import를 적용하면 declare const가 제대로 적용되지 않음.
// import 사용시 아래의 example이 적용되지 않아 Workaround로 require를 사용해봤으나 제대로 Import가 되지 않음.
// 따라서 parent folder와 child folder의 d.ts로 구분해 설정을 하는 방법을 생각해보는 것도 고려해볼 것.

// require('@react-navigation/native');
// const { useNavigation } = require('@react-navigation/native');
//const { StackNavigationProp } = require('@react-navigation/stack');

// declare const example: (hello: string) => string;

declare module '@react-navigation/native' {
  export function useNavigation(): StackNavigationProp<any>;
}

Advanced 개선방안

  1. Parent directory parent.d.ts

     // project components와는 관계없는 third party libraries 등
     import '@react-navigation/native';
     import { useNavigation } from '@react-navigation/native';
     import { StackNavigationProp } from '@react-navigation/stack';
    
     declare module '@react-navigation/native' {
       export function useNavigation(): StackNavigationProp<any>;
     }
    
  2. Child directory src.d.ts

     // project와 관련된 global type 지정
     type Measure = string;
    
     declare const example: (hello: string) => string;
    
     declare module 'assets/*.png' {
       const value: any;
       export = value;
     }
    
  3. tsconfig.json 설정

     {
       ...
       "include": ["**/*.d.ts"],
       ...
     }
    

참조

  1. Stackoverflow

  2. Typescript

저작권

크리에이티브 커먼즈 라이선스
이 저작물은 크리에이티브 커먼즈 저작자표시-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.