typeRoots 오해 --TypeScript에서 npm에서 설치한 패키지에 형식 정의 파일(*.d.ts)이 없을 때의 올바른 처리 방법

12231 단어 TypeScripttsconfig

요약


npm에 설치된 패키지에 유형 정의 파일*.d.ts이 존재하지 않는 상황에서 자신의 유형 정의 파일을 만들고 다음 1, 2의 설정을 통해 import에서 유형 정의 내용을 적용할 수 있습니다.
  • TypeScript 옵션baseUrlpaths의 조합을 통해 유형 정의 파일의 경로
  • 를 지정합니다.
  • 유형 정의 파일에서 declare module "xxx" { ... } 외부 모듈의 환경 선언
  • 어떤 경우 TypeScript 옵션typeRoots도 이 점을 실현할 수 있지만, typeRoots import에서 무효이기 때문에 실제로는 상기 목적에 사용할 수 없습니다.
    (import는 typeRoots에서 지정한 디렉터리에서 형식 정의 파일을 찾지 않습니다.)

    해설


    TypeScript로 프로그램을 쓸 때 npm에 패키지가 설치되어 있으면 패키지의 형식 정의 파일 *.d.ts 을 제공하지 않을 수 있습니다 @types/xxx 패키지도 없습니다.
    이 경우 strict 옵션 (또는 noImplicitAny 옵션) 을 사용하는 환경에서 구축 오류는 import 패키지를 시도할 때 형식 정의 파일을 찾을 수 없기 때문입니다.
    또한 상기 이외의 환경에서는 구축 오류가 발생하지 않지만 import의 대상과 함수가 any형이 되기 때문에 존재하지 않는 함수와 상수를 호출해도 오류가 발생하지 않으며 TypeScript의 유형 검사의 장점을 충분히 활용하지 못한다.
    import * as mod1 from "mod1";
    
    // mod1パッケージをnpmからインストールしていたとしても、型定義ファイルが存在しなければ、strict環境ではビルドエラーとなる
    //
    // エラーの内容は下記:
    // モジュール 'mod1' の宣言ファイルが見つかりませんでした。'/home/.../node_modules/mod1/index.js' は暗黙的に 'any' 型になります。
    // Try `npm install @types/mod1` if it exists or add a new declaration (.d.ts) file containing `declare module 'mod1';`ts(7016)
    
    이런 상황에서 단독제작mod1모듈의 유형정의파일mod1.d.ts으로import시 이 유형정의의 내용을 반영하는 방법은 크게 3가지가 있다.

  • TypeScript 옵션typeRoots에서 배치 유형 정의 파일의 디렉토리 지정
    tsconfig.json
    {
      "compilerOptions": {
        "typeRoots": ["node_modules/@types", "src/@types"],   // src/@types ディレクトリの中にある型定義を読み込ませたい
        ...
      }
    }
    

  • 유형 스크립트 옵션 지정baseUrl, paths 유형 정의 파일에 조합된 경로
    tsconfig.json
    {
      "compilerOptions": {
        "baseUrl": "src/typings" ,   // src/typings ディレクトリを起点とする (pathsの指定時は必須)
        "paths": {
          "mod1": ["mod1.d.ts"] // "mod1" のimport時に src/typings/mod1.d.ts を読み込ませる
                                // ※拡張子は省略可能のため、"mod1" や "mod1.d" も可
                                // ※このパス指定は省略可能で、省略した場合は自動的に src/typings/mod1.d.ts や src/typings/mod1/index.d.ts などを検索する
        },
        ...
      }
    }
    
    참고: TypeScript2.0의 Module Resolution Enhancements 정보@Quramy님의 보도

  • 임의의 유형 정의 파일에서 외부 모듈mod1에 대한 환경 광 선언
    mytypes/mod1.d.ts
    declare module "mod1" { // 外部モジュール「mod1」として宣言
        export function func1(): void;
        export function func2(): void;
    }
    
    ※ 이 모든 유형 정의 파일은 tsconfig.json 과 같은 층 이하이면 어느 곳에나 배치할 수 있습니다.
  • 그러나 이 1,2,3의 1의'typeRoots에 배치 유형 정의 파일의 디렉터리를 지정'하는 방법은 실제로import에 반영된 방법이 정확하지 않다.typeRoots에서 형식 정의 파일의 경로를 지정하면 실제import의 결과는 구축 오류 또는 any 입니다.
    ※ 상기 절차와 오류 확인에 대해서는 다음 설명검증 프로세스을 참조하십시오.

    과연 type Roots가 무엇인지.

    typeRoots는 삼중 사선 명령을 참조하는 경우에만 효과가 발생합니다.
    예를 들어, 참조 mod1 의 경우 다음 모듈 typeRoots mod1 에 정의 파일을 포함할 수 있습니다 (import에 반영되지 않고 구축 대상에 포함될 뿐).
    /// <reference types="mod1" />
    
    그러나 이 지정은 거의 baseUrlpaths의 조합으로 대체할 수 있고 이쪽의 조합이라면 import 때도 형식 정의 파일의 내용을 반영할 수 있기 때문에 더욱 광범위한 상황에 대응할 수 있다.
    따라서 baseUrlpaths가 설치된 지 3년이 지난 지금 상술/// <reference types="mod1" />typeRoots 모두 사용할 필요가 없다고 생각합니다./// <reference ... />은(는) tslint에서 수정 객체로 감지됨
    참조: typeRoots is not resolved as part of compilation #27026(TypeScript 공식 저장소의 Issue)

    왜 실제로 효과가 없는 typeRoots를 사용해서 전파됩니까?


    정확한 원인은 알 수 없지만 아마도 다음과 같은 이유 때문일 것이다.
  • strict(또는 noImplicitAny 옵션이 잘못되면 유형 정의 파일의 내용을 반영하지 않아도 any 이 되지만 구축 오류가 되지 않습니다.따라서 실제 시도에서 형식 정의 파일의 내용이 반영되지 않은 것을 알아차리기 어렵다
  • typeRoots의 지정과 declare module "xxx" { ... }의 모듈에 대한 환경 선언을 조합하면 typeRoots 덕분에 형식 정의 파일을 읽은 것처럼 보일 수 있습니다
  • TypeScript의 유형 정의는 검색과 import의 구조 자체가 복잡하기 때문에 이해하기 어렵다
  • 혹시 이전 버전의 TypeScript가 효과가 있을까요?(미확인)
  • 실제로 저도 TypeScript를 사용하기 시작한 지 1-2년이 되었지만 며칠 전까지는 이 사실을 눈치채지 못하고 typeRoots 옵션을 사용해 왔습니다.새 코드를 쓸 때 strict 옵션을 사용하지 않았다면 지금도 눈치채지 못했을 것이다.

    검증 프로세스


    node.js와 yarn이 설치된 환경에서 다음 절차를 수행하면import에 반영되지 않을 수 있습니다typeRoots.

  • 새 디렉터리에서 다음 명령을 실행하여 유형 스크립트 환경을 만듭니다.
    % yarn add typescript
    % yarn tsc --init   # 推奨設定でtsconfig.jsonを初期化 (strictオプションも有効になる)
    

  • pokemon-names-and-types 패키지 설치(이 패키지에는 유형 정의 파일이 없음)
    % yarn add pokemon-names-and-types
    

  • 다음과 같은 파일 만들기 main.tsmain.ts
    import { pkmn } from 'pokemon-names-and-types'
    
    console.log("Go! %s!", pkmn.random());
    

  • 같은 디렉터리에 새 types 디렉터리와 types/pokemon-names-and-types 디렉터리를 만들고 그 아래에 index.d.ts 디렉터리를 만듭니다package.json 존재하지 않는 경우 유형 스크립트 위치 확인 규칙 표준으로 읽어들여야 함index.d.tstypes/pokemon-names-and-types/index.d.ts
    interface PokemonObj {
        random: () => string;
    }
    export var pkmn: PokemonObj;
    

  • 설정tsconfig.jsontypeRoots 옵션
    tsconfig.json
        // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
        "typeRoots": ["./node_modules/@types", "./types"],                       /* List of folders to include type definitions from. */
        // "types": [],                           /* Type declaration files to be included in compilation. */
    
    

  • 구축 실행 - 유형 정의 파일을 찾을 수 없어 구축 오류가 발생했습니다.
    % yarn tsc
    $ /home/user1/dir1/node_modules/.bin/tsc
    main.ts:1:22 - error TS7016: Could not find a declaration file for module 'pokemon-names-and-types'. 
    '/home/user1/dir1/node_modules/pokemon-names-and-types/dist/main.js' implicitly has an 'any' type.
      Try `npm install @types/pokemon-names-and-types` if it exists or add a new declaration (.d.ts) file containing `declare module 'pokemon-names-and-types';`
    
    1 import { pkmn } from 'pokemon-names-and-types'
                           ~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Found 1 error.
    
  • 끝내다


    "pokemon-names-and-typesimport에서 작용하지 않는다"는 보도를 전달하기 위해서였지만 생각보다 길었다
    이 글을 읽고 TypeScript가 유형 정의 파일의 검색 구조와 typeRoots, typeRoots, baseUrl의 역할에 대한 이해를 조금 깊게 하기를 바랍니다.(이 일대의 구조를 잘 몰라서 힘들어요...)
    의견, 소감, 잘못된 지적, 혹은'기사의 이곳이 이해하기 어려우니 수정해 달라'는 요구가 있다면 본 기사의 논평과 Twitter 에서 메시지를 보내주시면 기쁩니다.
    또한,'import시 어떤 순서로 형식 정의 파일을 검색하는지 알고 싶은 사람은 아래 링크에 상세한 설명이 있으니 여기를 참조하십시오.나는 이 글을 쓸 때도 아래 페이지의 내용을 참고했다.

  • TypeScript Handbook 읽기(16.Module Resolution)(공식 핸드북의 @murank의 일본어 번역)

  • Type Script Deep Dive 일본어-Fe Module 상세 정보(Yohamata를 포함한 자원봉사자의 TypeScript Deep Dive의 일본어 번역)
  • 좋은 웹페이지 즐겨찾기