TypeScript 2 : 유형이 지정되지 않은 npm 모듈에 대한 사용자 지정 입력


93

다른 곳에 게시 된 제안을 시도한 후 , 유형이 지정되지 않은 NPM 모듈을 사용하는 typescript 프로젝트를 실행할 수 없다는 것을 알게되었습니다. 아래는 최소한의 예와 내가 시도한 단계입니다.

이 최소한의 예에서는 lodash기존 유형 정의가없는 척합니다 . 따라서 우리는 패키지를 무시 @types/lodash하고 타이핑 파일 lodash.d.ts을 프로젝트 에 수동으로 추가하려고합니다 .

폴더 구조

  • node_modules
    • Lodash
  • src
    • foo.ts
  • 타이핑
    • 커스텀
      • lodash.d.ts
    • 글로벌
    • index.d.ts
  • package.json
  • tsconfig.json
  • typings.json

다음으로 파일.

파일 foo.ts

///<reference path="../typings/custom/lodash.d.ts" />
import * as lodash from 'lodash';

console.log('Weeee');

파일 lodash.d.ts은 원본 @types/lodash패키지 에서 직접 복사됩니다 .

파일 index.d.ts

/// <reference path="custom/lodash.d.ts" />
/// <reference path="globals/lodash/index.d.ts" />

파일 package.json

{
  "name": "ts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "typings": "./typings/index.d.ts",
  "dependencies": {
    "lodash": "^4.16.4"
  },
  "author": "",
  "license": "ISC"
}

파일 tsconfig.json

{
  "compilerOptions": {
    "target": "ES6",
    "jsx": "react",
    "module": "commonjs",
    "sourceMap": true,
    "noImplicitAny": true,
    "experimentalDecorators": true,
    "typeRoots" : ["./typings"],
    "types": ["lodash"]
  },
  "include": [
    "typings/**/*",
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

파일 typings.json

{
    "name": "TestName",
    "version": false,
    "globalDependencies": {
        "lodash": "file:typings/custom/lodash.d.ts"
    }
}

보시다시피 타이핑을 가져 오는 여러 가지 방법을 시도했습니다.

  1. 직접 가져 오기 foo.ts
  2. (A)에 의해 typings속성package.json
  3. 사용 typeRoots하여tsconfig.json 파일로typings/index.d.ts
  4. 명시 적으로 사용하여 types의를tsconfig.json
  5. types디렉토리 를 포함하여tsconfig.json
  6. 사용자 정의 typings.json파일을 만들고 실행하여typings install

그러나 Typescript를 실행할 때 :

E:\temp\ts>tsc
error TS2688: Cannot find type definition file for 'lodash'.

내가 뭘 잘못하고 있죠?

답변:


206

불행히도 이러한 사항은 현재 잘 문서화되어 있지 않지만 작동 할 수 있다고하더라도 구성을 검토하여 각 부분이 수행하는 작업과 typescript가 입력을 처리하고로드하는 방법과 관련되는 방식을 이해하도록하겠습니다.

먼저 수신 한 오류를 살펴 보겠습니다.

error TS2688: Cannot find type definition file for 'lodash'.

이 오류는 실제로 가져 오기 또는 참조 또는 ts 파일의 어디에서나 lodash를 사용하려는 시도에서 발생하지 않습니다. 오히려 typeRootstypes속성 을 사용하는 방법에 대한 오해에서 비롯된 것이므로 이에 대해 좀 더 자세히 살펴 보겠습니다.

에 대한 건 typeRoots:[]types:[]속성들이 있다는 것입니다 NOT 임의의 선언 (로드 범용 방법 *.d.ts) 파일을.

이 두 속성은 NPM 패키지 에서 타이핑 선언을 패키징하고로드 할 수있는 새로운 TS 2.0 기능과 직접 관련이 있습니다. .

이는 NPM 형식의 폴더 (예 : package.json 또는 index.d.ts 포함 된 폴더)에서만 작동한다는 점을 이해하는 것이 매우 중요합니다 .

기본값 typeRoots은 다음과 같습니다.

{
   "typeRoots" : ["node_modules/@types"]
}

기본적으로 이것은 typescript가 node_modules/@types폴더 로 이동하여 찾은 모든 하위 폴더를 npm 패키지 로로드하려고 시도 함을 의미 합니다 .

폴더에 npm 패키지와 같은 구조가 없으면 이것이 실패한다는 것을 이해하는 것이 중요합니다.

이것은 귀하의 경우에 일어나는 일이며 초기 오류의 원인입니다.

typeRoot를 다음으로 전환했습니다.

{
    "typeRoots" : ["./typings"]
}

즉, typescript는 이제 ./typings폴더에서 하위 폴더를 검색합니다. 찾은 각 하위 폴더를 npm 모듈로로드하려고합니다.

따라서 방금 typeRoots가리 키도록 설정 ./typings했지만 아직 types:[]속성 설정 이없는 것으로 가정 해 봅시다 . 다음과 같은 오류가 표시 될 수 있습니다.

error TS2688: Cannot find type definition file for 'custom'.
error TS2688: Cannot find type definition file for 'global'.

이것은 폴더를 tsc스캔 ./typings하고 하위 폴더 customglobal. 그런 다음이를 npm 패키지 유형 입력으로 해석하려고 시도하지만 이 폴더에 index.d.ts또는 이 없으므로 package.json오류가 발생합니다.

이제 types: ['lodash']설정 하려는 속성 에 대해 조금 이야기 해 봅시다 . 이것은 무엇을합니까? 기본적으로 typescript는 내에서 찾은 모든 하위 폴더를 로드 합니다 typeRoots. types:속성 을 지정하면 특정 하위 폴더 만로드됩니다.

귀하의 경우에는 ./typings/lodash폴더 를로드하라고 말하고 있지만 존재하지 않습니다. 이것이 당신이 얻는 이유입니다 :

error TS2688: Cannot find type definition file for 'lodash'

그래서 우리가 배운 것을 요약합시다. 소개 2.0 타이프 라이터 typeRootstypes패키지로 로딩 선언 파일 NPM 패키지 . d.tsnpm 패키지 규칙을 따르는 폴더에 포함되지 않은 사용자 지정 입력 또는 단일 느슨한 파일이있는 경우이 두 가지 새 속성은 사용하려는 것이 아닙니다. Typescript 2.0은 이것이 소비되는 방식을 실제로 변경하지 않습니다. 여러 표준 방법 중 하나로 컴파일 컨텍스트에 이러한 파일을 포함하기 만하면됩니다.

  1. .ts파일 에 직접 포함 : ///<reference path="../typings/custom/lodash.d.ts" />

  2. ./typings/custom/lodash.d.ts귀하의 files: []재산에 포함 됩니다 .

  3. 포함 ./typings/index.d.ts당신의 files: []다음 재귀 적으로 다른 typings를 포함하는 재산 (.

  4. 추가 ./typings/**includes:

바라건대,이 토론을 기반으로하여 tsconfig.json만든 변경 사항이 다시 작동 하는 이유를 알 수있을 것입니다.

편집하다:

내가 언급하는 것을 잊은 한 가지는 typeRootsand typesproperty는 전역 선언 의 자동 로딩 에만 유용하다는 것입니다 .

예를 들어

npm install @types/jquery

그리고 당신이 JQuery와 유형 패키지가 자동으로로드됩니다 그런 다음, 기본 tsconfig을 사용하고 $더 이상을 할 필요 wihtout 모든 스크립트를 통해 사용할 수 있습니다 ///<reference/>또는import

typeRoots:[]속성은 유형 패키지 가 자동으로로드 되는 위치에서 추가 위치를 추가하기위한 것입니다.

types:[]재산의 주요 사용 사례는 (빈 배열로 설정하여) 자동로드 동작을 비활성화하는 것입니다, 다음 만이 전 세계적으로 포함 할 특정 유형을 나열.

다양한 유형의 패키지를로드하는 다른 방법 typeRoots은 new ///<reference types="jquery" />지시문 을 사용하는 것 입니다. 알아 차리는 types대신 path. 다시 말하지만 이것은 전역 선언 파일, 일반적으로 import/export.

자, 여기에 typeRoots. 나는 그것이 typeRoots모듈의 글로벌 포함에 관한 것이라고 말했습니다 . 그러나 설정에 @types/folder관계없이 표준 모듈 해상도에도 포함됩니다 typeRoots.

특히, 명시 적으로 가져 오기 모듈은 항상 모든 우회 includes, excludes, files, typeRootstypes옵션. 그래서 당신이 할 때 :

import {MyType} from 'my-module';

위에서 언급 한 모든 속성은 완전히 무시됩니다. 시 관련 특성 모듈의 해상도가 있습니다 baseUrl, paths그리고 moduleResolution.

사용하는 경우 기본적으로, node모듈의 해상도를,이 파일 이름에 대한 검색을 시작합니다 my-module.ts, my-module.tsx, my-module.d.ts폴더에서 시작하면 가리키는 baseUrl구성.

이 파일을 찾지 못하면, 그것은라는 폴더를 찾습니다 my-module다음 검색 package.json로모그래퍼 typings가있는 경우, 재산 package.json또는 더 typings그것을 말하는 내부 속성이있는 파일은 다음 검색합니다로드하지 않으려면 index.ts/tsx/d.ts해당 폴더 내에서.

그래도 성공하지 못하면 .NET node_modulesFramework에서 시작 하는 폴더 에서 이와 동일한 항목을 검색 합니다 baseUrl/node_modules.

또한 이러한 항목을 찾지 못하면 baseUrl/node_modules/@types동일한 항목을 모두 검색 합니다.

아직 아무것도 발견하지 않은 경우는 상위 디렉토리로 이동 시작하고 검색합니다 node_modules하고 node_modules/@types있다. 파일 시스템의 루트에 도달 할 때까지 디렉토리를 계속 올라갑니다 (프로젝트 외부에 노드 모듈을 가져 오는 경우도 포함).

제가 강조하고 싶은 것은 모듈 해상도가 설정 한 것을 완전히 무시한다는 typeRoots것입니다. 따라서 구성한 경우 typeRoots: ["./my-types"]명시 적 모듈 확인 중에 검색되지 않습니다. 더 이상 가져 오거나 참조 할 필요없이 전체 응용 프로그램에서 사용할 수 있도록하려는 전역 정의 파일을 저장할 수있는 폴더 역할 만합니다.

마지막으로 경로 매핑 (즉, paths속성)으로 모듈 동작을 재정의 할 수 있습니다 . 예를 들어, typeRoots모듈을 해결하려고 할 때 사용자 정의 를 참조하지 않는다고 언급했습니다 . 그러나 마음에 들면 다음과 같이이 동작을 수행 할 수 있습니다.

"paths" :{
     "*": ["my-custom-types/*", "*"]
 }

이 작업은 왼쪽과 일치하는 모든 가져 오기에 대해 가져 오기를 포함하기 전에 오른쪽에서와 같이 가져 오기를 수정 해보십시오 ( *오른쪽에있는 것은 초기 가져 오기 문자열을 나타냅니다. 예를 들어 가져 오는 경우 :

import {MyType} from 'my-types';

먼저 다음과 같이 작성한 것처럼 가져 오기를 시도합니다.

import {MyType} from 'my-custom-types/my-types'

그런 다음 찾지 못하면 접두사없이 다시 시도합니다 (배열의 두 번째 항목 *은 초기 가져 오기를 의미합니다.

따라서 이러한 방법으로 추가 폴더를 추가하여 사용자 정의 선언 파일 또는 .ts원하는 사용자 정의 모듈 을 검색 할 수 import있습니다.

특정 모듈에 대한 사용자 지정 매핑을 만들 수도 있습니다.

"paths" :{
   "*": ["my-types", "some/custom/folder/location/my-awesome-types-file"]
 }

이것은 당신이 할 수 있도록

import {MyType} from 'my-types';

그러나 다음에서 해당 유형을 읽으십시오. some/custom/folder/location/my-awesome-types-file.d.ts


1
자세한 답변에 감사드립니다. 솔루션은 독립적으로 작동하지만 잘 섞이지 않습니다. 상황이 명확 해 지므로 현상금을드립니다. 몇 가지 더 많은 점에 답할 시간을 찾을 수 있다면 다른 사람들에게 정말 도움이 될 것입니다. (1) typeRoots가 특정 폴더 구조 만 허용하는 이유가 있습니까? 임의적으로 보입니다. (2) typeRoots를 변경하면 typescript는 사양과 달리 node_modules에 @types 폴더를 여전히 포함합니다. (3) 타이핑 목적과 paths는 무엇 이고 어떻게 다른 include가요?
Jodiug

1
답변을 수정했습니다. 질문이 더 있으면 알려주세요.
dtabuenc

1
고마워요, 나머지를 읽고 와우. 이 모든 것을 찾는 당신에게 소품. 직장에서 불필요하게 복잡한 행동이 많이있는 것 같습니다. Typescript가 향후 구성 속성을 좀 더 자체 문서화 할 수 있기를 바랍니다.
Jodiug

1
에서이 답변에 대한 링크가 있어야 typescriptlang.org/docs/handbook/tsconfig-json.html
hgoebl

2
마지막 예는 다음과 같지 "paths" :{ "my-types": ["some/custom/folder/location/my-awesome-types-file"] }않습니까?
Koen.

6

편집 : 오래되었습니다. 위의 답변을 읽으십시오.

나는 아직도 이것을 이해하지 못하지만 해결책을 찾았습니다. 다음을 사용하십시오 tsconfig.json.

{
  "compilerOptions": {
    "target": "ES6",
    "jsx": "react",
    "module": "commonjs",
    "sourceMap": true,
    "noImplicitAny": true,
    "experimentalDecorators": true,
    "baseUrl": ".",
    "paths": {
      "*": [
        "./typings/*"
      ]
    }
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

를 제외한 typings.json폴더 아래의 모든 항목을 제거 합니다 . 또한 모든 참조를 제거하십시오.typingslodash.d.ts///...


3

"*": ["./types/*"] tsconfig 경로의이 줄은 2 시간의 어려움 후에 모든 것을 수정했습니다.

{
  "compilerOptions": {
    "moduleResolution": "node",
    "strict": true,
    "baseUrl": ".",
    "paths": {
      "*": ["./types/*"]
    },
    "jsx": "react",
    "types": ["node", "jest"]
  },
  "include": [
    "client/**/*",
    "packages/**/*"
  ],
  "exclude": [
    "node_modules/**/*"
  ]
}

유형 의 수준에 node_module 즉, 옆에 앉아 폴더 이름입니다 클라이언트 폴더 (또는 의 src 폴더) types/third-party-lib/index.d.ts
index.d.ts가 있다declare module 'third-party-lib';

참고 : 위의 구성은 불완전한 구성으로 유형, 경로, 포함 및 제외가 어떻게 생겼는지 알 수 있습니다.


1

나는 이것이 오래된 질문이라는 것을 알고 있지만 typescript 도구는 지속적으로 변화하고 있습니다. 이 시점에서 가장 좋은 옵션은 tsconfig.json의 "include"경로 설정에 의존하는 것입니다.

  "include": [
        "src/**/*"
    ],

기본적으로 특별히 변경하지 않는 한 모든 * .ts 및 모든 * .d.ts 파일 src/이 자동으로 포함됩니다. 사용자 지정 typeRoots및 사용자 지정없이 사용자 지정 형식 선언 파일을 포함하는 가장 쉽고 / 가장 좋은 방법이라고 생각합니다.types .

참고:


0

위에서 찾은 자세한 설명을 확장하기 위해 최근 관찰 한 내용 중 일부를 공유하고 싶습니다 . 먼저 VS Code는 작업 방식에 대해 종종 다른 의견을 가지고 있다는 점에 유의해야합니다.

최근에 작업 한 예를 보겠습니다.

src / app / components / plot-plotly / plot-plotly.component.ts :

/// <reference types="plotly.js" />
import * as Plotly from 'plotly.js';

VS Code는 다음과 같이 불평 할 수 있습니다. No need to reference "plotly.js", since it is imported. (no-reference import) tslint(1)

프로젝트를 시작하면 오류없이 컴파일되지만 해당 줄을 제거하면 시작 중에 다음 오류가 나타납니다.

ERROR in src/app/components/plot-plotly/plot-plotly.component.ts:19:21 - error TS2503: Cannot find namespace 'plotly'.

reference typesimport 문 뒤에 지시문을 배치하는 경우에도 동일한 오류 메시지가 나타납니다 .

중요 : /// <reference types="plotly.js" />은 유형 스크립트 파일의 앞에 있어야합니다! 관련 문서 참조 : 링크

삼중 슬래시 지시문은 포함하는 파일의 맨 위에서 만 유효합니다.

또한 tsconfig.json 및 typeRoot 섹션에 대한 문서를 읽는 것이 좋습니다. 링크

유형 패키지는 index.d.ts라는 파일이있는 폴더 또는 유형 필드가있는 package.json이있는 폴더입니다.

위의 참조 지시문은 다음 시나리오에서 작동합니다.

types / plotly.js / index.d.ts : ( 링크 )

  declare namespace plotly {
    export interface ...
  }

tsconfig.json :

  "compilerOptions": {
    ...
    "typeRoots": [
      "types/",
      "node_modules/@types"
    ],
    ...  

참고 : 위 설정에서 두 개의 "plotly.js"는 두 개의 다른 폴더 및 파일 (라이브러리 / 정의)을 의미합니다. 가져 오기는 "node_modules / plotly.js"폴더에 적용됩니다 (npm install plotly.js )에 적용되고 참조는 types / plotly.js에 적용됩니다.

내 프로젝트에서 VS Code 불평과 "two"plotly.js의 모호함을 해결하기 위해 다음 구성으로 끝났습니다.

  • 모든 파일이 원래 위치에 남아 있음
  • tsconfig.json :
  "compilerOptions": {
    ...
    "typeRoots": [
      "./",
      "node_modules/@types"
    ],
    ...  
  • src / app / components / plot-plotly / plot-plotly.component.ts :
  /// <reference types="types/plotly.js" />
  import * as Plotly from 'plotly.js';

  plotDemo() {

  // types using plotly namespace
  const chunk: plotly.traces.Scatter = {
      x: [1, 2, 3, 4, 5],
      y: [1, 3, 2, 3, 1],
      mode: 'lines+markers',
      name: 'linear',
      line: { shape: 'linear' },
      type: 'scatter'
  };

  // module call using Plotly module import
  Plotly.newPlot(...);
  }

내 시스템의 DevDeps :

  • "ts-node": "~ 8.3.0",
  • "tslint": "~ 5.18.0",
  • "typescript": "~ 3.7.5"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.