ไม่พบไฟล์ประกาศสำหรับโมดูล 'module-name' '/path/to/module-name.js' มีประเภท 'any'


303

ฉันอ่านการทำงานของความละเอียดโมดูล TypeScript

ฉันมีพื้นที่เก็บข้อมูลต่อไปนี้: @ TS-สแต็ค / ดิ หลังจากรวบรวมโครงสร้างไดเรกทอรีดังต่อไปนี้:

├── dist
   ├── annotations.d.ts
   ├── annotations.js
   ├── index.d.ts
   ├── index.js
   ├── injector.d.ts
   ├── injector.js
   ├── profiler.d.ts
   ├── profiler.js
   ├── providers.d.ts
   ├── providers.js
   ├── util.d.ts
   └── util.js
├── LICENSE
├── package.json
├── README.md
├── src
   ├── annotations.ts
   ├── index.ts
   ├── injector.ts
   ├── profiler.ts
   ├── providers.ts
   └── util.ts
└── tsconfig.json

ใน package.json "main": "dist/index.js"ของฉันฉันเขียน

ใน Node.js ทุกอย่างทำงานได้ดี แต่ TypeScript:

import {Injector} from '@ts-stack/di';

ไม่พบไฟล์ประกาศสำหรับโมดูล '@ ts-stack / di' '/path/to/node_modules/@ts-stack/di/dist/index.js' มีประเภท 'any'

และถ้าฉันนำเข้าดังต่อไปนี้ทุกอย่างทำงานได้:

import {Injector} from '/path/to/node_modules/@ts-stack/di/dist/index.js';

ผมทำอะไรผิดหรือเปล่า?

คำตอบ:


295

นี่คือสองวิธีแก้ไขอื่น ๆ

เมื่อโมดูลไม่ใช่ของคุณ - ให้ลองติดตั้งประเภทจาก@types:

npm install -D @types/module-name

หากข้อผิดพลาดในการติดตั้งข้างต้น - ลองเปลี่ยนimportคำสั่งเป็นrequire:

// import * as yourModuleName from 'module-name';
const yourModuleName = require('module-name');

13
ถ้าคุณไม่สามารถหาชื่อได้ให้เรียกใช้สิ่งนี้สำหรับ TypeScript 2.0:npm install @types/node --save-dev
Ogglas

120
จะเกิดอะไรขึ้นถ้าโมดูลไม่มีแพ็คเกจ @types
Daniel Kmak

37
ฉันคิดว่าการใช้requireแทนที่จะimportเป็นรูปแบบการต่อต้านเล็กน้อย: เป็นการดีกว่าที่จะประกาศโมดูลใน.d.tsไฟล์ ดูคำตอบของฉันด้านล่าง
Retsam

2
ตัวอย่างการใช้งาน: const mdbreact = require('mdbreact'); const { Button, Card, CardBody, CardText, CardTitle, CardImage } = mdbreact;
Sgedda

1
นี่คือคำแนะนำที่ไม่ดี สิ่งนี้เป็นการลบล้างจุดประสงค์ของ TypeScript และทัศนคติทั่วไปของ FOSS ของ "สิ่งที่ง่ายพอสมควรที่จะมีส่วนร่วม" หากไม่มีการพิมพ์ a การค้นหาใครบางคนทำได้และไม่ได้เผยแพร่หรือส่งการประชาสัมพันธ์ด้วยการพิมพ์ของคุณหรือไม่ใช้ระบบการพิมพ์หากคุณต้องการหลีกเลี่ยง
Dave Mackintosh

265

หากคุณกำลังนำเข้าโมดูลของบุคคลที่สาม'foo'ที่ไม่มีการพิมพ์ใด ๆ ไม่ว่าจะเป็นในไลบรารีเองหรือใน@types/fooแพ็คเกจ (สร้างขึ้นจากที่เก็บDefinitelyTyped ) จากนั้นคุณสามารถทำให้ข้อผิดพลาดนี้หายไปโดยการประกาศโมดูลใน ไฟล์ที่มี.d.tsนามสกุล typescript มองหา.d.tsไฟล์ในสถานที่เดียวกันกับที่มันจะมีลักษณะปกติ.tsไฟล์: ตามที่ระบุไว้ภายใต้ "ไฟล์", "รวมถึง" และ "ยกเว้น" tsconfig.jsonใน

// foo.d.ts
declare module 'foo';

จากนั้นเมื่อคุณนำเข้ามันจะเป็นเพียงแค่พิมพ์เป็น fooany


อีกทางเลือกหนึ่งถ้าคุณต้องการพิมพ์งานของคุณเองคุณสามารถทำได้เช่นกัน:

// foo.d.ts
declare module 'foo' {
    export function getRandomNumber(): number
} 

จากนั้นจะรวบรวมอย่างถูกต้อง:

import { getRandomNumber } from 'foo';
const x = getRandomNumber(); // x is inferred as number

คุณไม่จำเป็นต้องให้การพิมพ์เต็มรูปแบบสำหรับโมดูลเพียงแค่บิตที่คุณใช้ (และต้องการการพิมพ์ที่เหมาะสม) ดังนั้นจึงเป็นเรื่องง่ายโดยเฉพาะอย่างยิ่งถ้าคุณใช้ API จำนวนเล็กน้อย


ในทางตรงกันข้ามถ้าคุณไม่สนใจเกี่ยวกับการพิมพ์ของไลบรารีภายนอกและต้องการให้ไลบรารีทั้งหมดที่ไม่มีการพิมพ์นำเข้าเป็นanyคุณสามารถเพิ่มสิ่งนี้ลงในไฟล์ที่มี.d.tsนามสกุล:

declare module '*';

ข้อดี (และข้อเสีย) ของสิ่งนี้คือคุณสามารถนำเข้าอะไรก็ได้และ TS จะรวบรวม


27
คอมไพเลอร์มองหาd.tsไฟล์ที่ไหน? คุณควรกำหนดค่าใด ๆ เช่นtypeRoots?
Tom

17
@ Tom มันจะมองหา.d.tsไฟล์ในสถานที่เดียวกันกับที่มันจะมีลักษณะปกติ.tsไฟล์: ตามที่ระบุไว้ "ไฟล์", "รวมถึง" และ "ยกเว้น" tsconfig.jsonใน ฉันจะไม่แนะนำให้ใช้typeRootsเพื่อจุดประสงค์นี้: มีไว้สำหรับตำแหน่งของโมดูลประเภทภายนอก (เช่นnode_modules/@types) ไม่ใช่.d.tsไฟล์แต่ละไฟล์
Retsam

3
ฉันได้รับ "ไฟล์ foo.d.ts ไม่ใช่โมดูล"
นาธาน H

2
ดูเหมือนว่าไฟล์ไวด์การ์ดนี้ต้องถูกเรียกว่า "typings.d.ts"
jacob

4
ฉันควรใส่.d.tsไฟล์นี้ไว้ที่ไหน?
tonix

127

หากคุณต้องการการแก้ไขด่วนเพียงเพิ่มสิ่งนี้ก่อนบรรทัดการนำเข้าของคุณ:

// @ts-ignore

7
ขอบคุณคำตอบที่มีประโยชน์ที่สุดสำหรับกรณีของฉัน
เดวิด

สิ่งนี้ทำให้เกิดข้อผิดพลาดใน eslint รุ่นที่ใหม่กว่า:error Do not use "// @ts-ignore" comments because they suppress compilation errors @typescript-eslint/ban-ts-ignore
Hykilpikonna

91

ความรู้สึกว่าเมื่อคุณกำลังมองออกไปสำหรับสองวันและพบว่ามันเช่นนี้เพียง แต่เอา.jsจาก"main": "dist/index.js"ในpackage.jsonและทุกอย่างทำงานได้ดี!

"main": "dist/index",

UPD : คำตอบนี้ญาติถ้าคุณมีแพคเกจ NPM ของคุณเองหากไม่ได้ - ดูคำตอบของฉันด้านล่าง

และหากคำตอบข้างต้นไม่ได้รับการแก้ไขให้นำเข้าโมดูลของคุณลองเพิ่มtypingsในpackage.json:

"main": "dist/index",
"typings": "dist/index",

แน่นอนที่นี่โฟลเดอร์dist- เป็นที่เก็บไฟล์โมดูลของคุณ


ฉันมาที่คำถามของคุณและคำตอบของคุณหลายครั้งในวันสุดท้ายและฉันต้องการเพิ่มว่าสิ่งที่ฉันหายไปคือการประกาศประเภทเหล่านั้นในไฟล์. d.ts ดังนั้นในกรณีของฉันโมดูลโหนดที่ติดตั้งมาโดยไม่มี ประเภท (และฉันไม่สามารถติดตั้ง explicity ประเภทของพวกเขา) เริ่มทำงานโดยประกาศพวกเขาในไฟล์นั้นโดยการเขียน "ประกาศโมดูล 'MYDesiredModule'
Juan

ขอบคุณ การเพิ่ม "typings": "dist / index" ไปยัง package.json ของฉันคือสิ่งที่ใช้ได้กับฉัน แปลกที่รหัส VS โยนข้อผิดพลาด typescript เมื่อฉันไม่ได้ใช้ TypeScript
phocks

ขอบคุณสำหรับความเข้าใจของคุณ! คุณช่วยบอกฉันหน่อยได้ไหมว่าทำไมคำจำกัดความของรหัส VS ไม่ทำงานสำหรับแพคเกจ npm ของฉันเองถ้าฉันพยายามไปที่คำจำกัดความ ฉันได้สร้างคำถามที่นี่และไม่มีโชคตอนนี้ ... stackoverflow.com/questions/59128917//
tonix

คุณต้องเพิ่มไฟล์ "index.d.ts" ในโฟลเดอร์ dist และใส่declare module "moduleName" ในระหว่างนี้
ซันนี่ซัน

42

โดยทั่วไปแล้ว TypeScript จะใช้กฎและการเพิ่มประเภทให้กับรหัสของคุณเพื่อให้ชัดเจนและแม่นยำยิ่งขึ้นเนื่องจากไม่มีข้อ จำกัด ใน Javascript TypeScript ต้องการให้คุณอธิบายข้อมูลของคุณเพื่อให้คอมไพเลอร์สามารถตรวจสอบรหัสของคุณและค้นหาข้อผิดพลาด คอมไพเลอร์จะแจ้งให้คุณทราบว่าคุณกำลังใช้ประเภทที่ไม่ตรงกันถ้าคุณไม่อยู่ในขอบเขตของคุณหรือคุณพยายามที่จะคืนค่าประเภทอื่น ดังนั้นเมื่อคุณใช้ไลบรารีและโมดูลภายนอกด้วย TypeScript พวกเขาจำเป็นต้องมีไฟล์ที่อธิบายประเภทในรหัสนั้น ไฟล์เหล่านั้นจะเรียกว่าประเภทไฟล์ประกาศd.tsที่มีการขยาย ชนิดการประกาศส่วนใหญ่สำหรับโมดูล npm นั้นถูกเขียนไปแล้วและคุณสามารถรวมมันได้โดยที่npm install @types/module_name(module_name เป็นชื่อของโมดูลที่มีประเภทที่คุณต้องการรวมไว้)

อย่างไรก็ตามมีโมดูลที่ไม่มีคำจำกัดความประเภทและเพื่อให้ข้อผิดพลาดหายไปและนำเข้าโมดูลโดยใช้import * as module_name from 'module-name'สร้างโฟลเดอร์typingsในรากของโครงการของคุณภายในสร้างโฟลเดอร์ใหม่ด้วยชื่อโมดูลของคุณและในนั้น โฟลเดอร์สร้างไฟล์และเขียนmodule_name.d.ts declare module 'module_name'หลังจากนี้ไปที่tsconfig.jsonไฟล์ของคุณและเพิ่ม"typeRoots": [ "../../typings", "../../node_modules/@types"]ในcompilerOptions(พร้อมพา ธ สัมพันธ์ที่เหมาะสมไปยังโฟลเดอร์ของคุณ) เพื่อให้ TypeScript ทราบว่าจะสามารถหาคำจำกัดความประเภทของไลบรารีและโมดูลของคุณและเพิ่มคุณสมบัติใหม่"exclude": ["../../node_modules", "../../typings"]ลงในไฟล์ได้ นี่คือตัวอย่างลักษณะของไฟล์ tsconfig.json ของคุณ:

{
    "compilerOptions": {
        "module": "commonjs",
        "noImplicitAny": true,
        "sourceMap": true,
        "outDir": "../dst/",
        "target": "ESNEXT",
        "typeRoots": [
            "../../typings",
            "../../node_modules/@types"
        ]
    },
    "lib": [
            "es2016"
    ],
    "exclude": [
        "../../node_modules",
        "../../typings"
    ]
}

เมื่อทำสิ่งนี้ข้อผิดพลาดจะหายไปและคุณจะสามารถปฏิบัติตามกฎ ES6 และ TypeScript ล่าสุดได้


มันใช้งานได้สำหรับฉันถ้าฉันตั้งชื่อไฟล์การindex.d.tsพิมพ์ นอกเหนือจากนั้นนี่เป็นทางออกเดียวที่ใช้ได้สำหรับฉัน
Chris Haines

21

สำหรับคนอื่นที่อ่านข้อความนี้ลองเปลี่ยนชื่อไฟล์. js เป็น .ts

แก้ไข: คุณสามารถเพิ่มลง"allowJs": trueในไฟล์ tsconfig ของคุณได้


ใช่มีปัญหาเดียวกันกับ "ปฏิกิริยาฟิวชั่นชาร์ต" และวิธีการแก้ปัญหานี้ทำงานเหมือนมีเสน่ห์
yawningphantom

16

วิธีนี้ใช้ได้กับฉัน:

1. เพิ่มการประกาศของคุณเองในไฟล์ประกาศเช่น index.d.ts (อาจอยู่ภายใต้รูทโครงการ)
declare module 'Injector';
2. เพิ่ม index.d.ts ของคุณใน tsconfig.json
  {
    "compilerOptions": {
        "strictNullChecks": true,
        "moduleResolution": "node",
        "jsx": "react",
        "noUnusedParameters": true,
        "noUnusedLocals": true,
        "allowSyntheticDefaultImports":true,
        "target": "es5",
        "module": "ES2015",
        "declaration": true,
        "outDir": "./lib",
        "noImplicitAny": true,
        "importHelpers": true
      },
      "include": [
        "src/**/*",
        "index.d.ts",   // declaration file path
      ],
      "compileOnSave": false
    }

- แก้ไข: เครื่องหมายคำพูดที่จำเป็นรอบชื่อโมดูล


4

ฉันมีปัญหาเดียวกันโดยใช้โมดูลโหนดกับแอปพลิเคชันตอบโต้ที่เขียนด้วย typescript npm i --save my-moduleโมดูลที่ได้รับการติดตั้งเรียบร้อยแล้วโดยใช้ มันเขียนใน javascript และส่งออกClientชั้นเรียน

ด้วย:

import * as MyModule from 'my-module';
let client: MyModule.Client = new MyModule.Client();

การรวบรวมล้มเหลวโดยมีข้อผิดพลาด:

Could not find a declaration file for module 'my-module'. 
'[...]/node_modules/my-module/lib/index.js' implicitly has an 'any' type.
  Try `npm install @types/my-module` if it exists or add a new declaration (.d.ts) file containing `declare module 'my-module';`

@types/my-moduleไม่มีอยู่ดังนั้นฉันจึงเพิ่มmy-module.d.tsไฟล์ถัดจากไฟล์ที่my-moduleนำเข้าโดยมีบรรทัดที่แนะนำ ฉันได้รับข้อผิดพลาด:

Namespace '"my-module"' has no exported member 'Client'.

ลูกค้าจะถูกส่งออกและใช้งานได้ตามปกติถ้าฉันใช้ในแอพ js นอกจากนี้ข้อความก่อนหน้าบอกฉันว่าคอมไพเลอร์กำลังมองหาไฟล์ที่ถูกต้อง ( /node_modules/my-module/lib/index.jsถูกกำหนดในmy-module/package.json "main"องค์ประกอบ)

ฉันแก้ไขปัญหาด้วยการบอกคอมไพเลอร์ฉันไม่สนใจโดยปริยายanyนั่นคือฉันตั้งค่าfalseเป็นบรรทัดต่อไปนี้ของtsconfig.jsonไฟล์:

    "noImplicitAny": false,

14
ฉันหมายความว่ามันใช้งานได้ แต่คุณสูญเสียความสามารถในการพิมพ์รหัสที่เหลือของคุณอย่างเคร่งครัด มันไม่ได้เป็นวิธีแก้ปัญหาที่ดี
phillyslick

3

ง่าย ๆ ที่จะแก้ไขคุณคือ:

// example.d.ts
declare module 'foo';

หากคุณต้องการประกาศส่วนต่อประสานของวัตถุ (แนะนำสำหรับโครงการขนาดใหญ่) คุณสามารถใช้:

// example.d.ts
declare module 'foo'{
    // example
    export function getName(): string
}

ใช้อย่างไร ที่เรียบง่าย ..

const x = require('foo') // or import x from 'foo'
x.getName() // intellisense can read this

2

ฉันได้รับสิ่งนี้เช่นกันทำให้ฉันงุนงงอยู่พักหนึ่งแม้จะมีโมดูลและประเภทที่ติดตั้งไว้แล้วและโหลด IDE ของฉันอีกหลายครั้ง

สิ่งที่แก้ไขในกรณีของฉันคือยุติกระบวนการเทอร์มินัลการลบการnode_modulesล้างแคชตัวจัดการแพ็กเกจโหนดและทำการใหม่installจากนั้นโหลดเอดิเตอร์อีกครั้ง


2

น่าเสียดายที่อยู่นอกมือของเราไม่ว่านักเขียนแพ็คเกจจะรบกวนไฟล์ประกาศ สิ่งที่ฉันมักจะทำคือมีไฟล์index.d.tsที่จะมีไฟล์ประกาศทั้งหมดที่หายไปจากแพ็คเกจต่างๆ:

Index.ts:

declare module 'v-tooltip';
declare module 'parse5';
declare module 'emoji-mart-vue-fast';


0

ฉันลองทุกอย่างที่นี่ แต่สำหรับฉันมันเป็นปัญหาที่แตกต่างอย่างสิ้นเชิง: ฉันต้องลบออกจาก*.d.tsคำสั่งการนำเข้าของฉัน:

import { SomeModuleType } from '3rd-party-module';

หลังจากลบข้อผิดพลาดออกไป ...

การทำให้กระจ่าง : เมื่อเราประกาศโมดูลใน*.d.tsไฟล์มันจะถูกรับโดยอัตโนมัติโดยคอมไพเลอร์ typescript เป็นโมดูลล้อมรอบ (โมดูลที่คุณไม่จำเป็นต้องนำเข้าอย่างชัดเจน) เมื่อเราระบุimport ... from ...ไฟล์ตอนนี้จะกลายเป็นโมดูลปกติ (ES6) และด้วยเหตุนี้จะไม่ถูกเลือกโดยอัตโนมัติ ดังนั้นหากคุณยังต้องการให้มันทำงานเป็นโมดูลโดยรอบให้ใช้สไตล์การนำเข้าที่แตกต่างกันดังนี้:

type MyType: import('3rd-party-module').SomeModuleType;

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.