Nie można znaleźć pliku deklaracji dla modułu „nazwa-modułu”. „/path/to/module-name.js” niejawnie ma typ „dowolny”

303

Czytam, jak działa rozdzielczość modułu TypeScript .

Mam następujące repozytorium: @ ts-stack / di . Po skompilowaniu struktura katalogów wygląda następująco:

├── 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

W moim pakiecie.json napisałem "main": "dist/index.js".

W Node.js wszystko działa dobrze, ale TypeScript:

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

Nie można znaleźć pliku deklaracji dla modułu „@ ts-stack / di”. „/path/to/node_modules/@ts-stack/di/dist/index.js” niejawnie ma typ „dowolny”.

A jednak, jeśli zaimportuję w następujący sposób, wszystko działa:

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

Co ja robię źle?

ktretyak
źródło

Odpowiedzi:

295

Oto dwa inne rozwiązania

Jeśli moduł nie jest twój - spróbuj zainstalować typy z @types:

npm install -D @types/module-name

Jeśli powyższe błędy instalacyjne - spróbuj zmienić importinstrukcje na require:

// import * as yourModuleName from 'module-name';
const yourModuleName = require('module-name');
ktretyak
źródło
13
Jeśli nie możesz znaleźć nazwy, uruchom ją dla TypeScript 2.0:npm install @types/node --save-dev
Ogglas
120
Co jeśli moduł nie ma pakietu @types?
Daniel Kmak
37
Myślę, że używanie requirezamiast importjest trochę anty-wzorcem: lepiej zadeklarować moduł w .d.tspliku; zobacz moją odpowiedź poniżej.
Retsam
2
Przykładowe użycie: const mdbreact = require('mdbreact'); const { Button, Card, CardBody, CardText, CardTitle, CardImage } = mdbreact;
Sgedda,
1
To kiepska rada. To całkowicie neguje sens TypeScript i ogólne podejście FOSS, że „coś łatwego jest warte wniesienia wkładu”. Jeśli brakuje wpisywania a, poszukaj kogoś, kto to zrobił i nie opublikował lub nie przesyła dokumentu PR ze swoimi wpisaniami lub nie używa systemu pisania, jeśli chcesz go obejść.
Dave Mackintosh,
265

Jeśli importujesz moduł innej firmy 'foo', który nie zapewnia żadnych typów, ani w samej bibliotece, ani w @types/foopakiecie (generowanym z repozytorium DefinitelyTyped ), możesz usunąć ten błąd, deklarując moduł w pliku plik z .d.tsrozszerzeniem. TypeScript szuka .d.tsplików w tych samych miejscach, w których będzie szukać normalnych .tsplików: jak określono w „files”, „include” i „exclude” w tsconfig.json.

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

Następnie po zaimportowaniu foozostanie wpisany jako any.


Alternatywnie, jeśli chcesz rzutować własne pisma, możesz to zrobić również:

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

Wtedy to skompiluje się poprawnie:

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

Nie musisz podawać pełnych typów dla modułu, wystarczy dla bitów, których faktycznie używasz (i chcesz odpowiednich typów), więc jest to szczególnie łatwe, jeśli używasz dość niewielkiej ilości API.


Z drugiej strony, jeśli nie przejmujesz się typowaniem bibliotek zewnętrznych i chcesz importować wszystkie biblioteki bez typowania any, możesz dodać to do pliku z .d.tsrozszerzeniem:

declare module '*';

Zaletą (i minusem) tego jest to, że możesz importować absolutnie wszystko, a TS się skompiluje.

Retsam
źródło
27
gdzie kompilator szuka d.tsplików? powinieneś podać jakąkolwiek konfigurację taką jak typeRoots?
Tom
17
@Tom Wyszukuje .d.tspliki w tych samych miejscach, w których będzie szukał normalnych .tsplików: jak określono „pliki”, „ dołącz ” i „wyklucz” w pliku tsconfig.json. Nie polecałbym używać typeRootsdo tego celu: jest to przeznaczone do lokalizacji modułów typu zewnętrznego (tj. node_modules/@types), A nie pojedynczych .d.tsplików.
Retsam,
3
Dostaję „plik foo.d.ts nie jest modułem”
Nathan H
2
Wygląda na to, że ten plik symboli wieloznacznych należy nazwać „typings.d.ts”
Jacob
4
Gdzie powinienem umieścić ten .d.tsplik?
tonix
127

Jeśli potrzebujesz szybkiej poprawki, po prostu dodaj ją przed linią importu:

// @ts-ignore
Liran H.
źródło
7
Dzięki, najbardziej przydatna odpowiedź w mojej sprawie.
David
Powoduje to błąd w późniejszych wersjach eslint:error Do not use "// @ts-ignore" comments because they suppress compilation errors @typescript-eslint/ban-ts-ignore
Hykilpikonna
91

To uczucie, gdy jesteś patrząc na dwa dni i znaleźć to tak: po prostu usunąć .jsz "main": "dist/index.js"w package.jsoni wszystko działa poprawnie!

"main": "dist/index",

UPD : ta odpowiedź względna, jeśli masz własny pakiet npm, jeśli nie - patrz moja odpowiedź poniżej .

A jeśli powyższa odpowiedź nie rozwiązany importu modułu, spróbuj po prostu dodać typingsw package.json:

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

Oczywiście tutaj folder dist- tam są przechowywane pliki modułu.

ktretyak
źródło
W ciągu ostatnich dni wielokrotnie podchodziłem do twojego pytania i odpowiedzi i chciałbym dodać, że brakowało mi zadeklarowania tych typów w pliku .d.ts, więc w moim przypadku zainstalowałem moduły węzłów, które były dostarczane bez typy (i nie byłem w stanie zainstalować Explicity ich typy) zaczęły działać, deklarując je w tym pliku, pisząc „zadeklaruj moduł„ MYDesiredModule ”
Juan
Dzięki. Dodanie „typings”: „dist / index” do mojego package.json było dla mnie skuteczne. Dziwne, że VS Code zgłasza błąd maszynopisu, gdy nawet nie używam TypeScript
wydzwaniają
Dziękujemy za wgląd! Czy możesz mi powiedzieć, dlaczego definicje VS Code nie działają dla mojego własnego pakietu npm, jeśli próbuję przejść do definicji? Stworzyłem tutaj pytanie i jak dotąd nie miałem szczęścia ... stackoverflow.com/questions/59128917/
tonix
musisz dodać plik „index.d.ts” do folderu dist i umieścić declare module "moduleName" w międzyczasie
Sunny Sun
42

TypeScript w zasadzie implementuje reguły i dodaje typy do twojego kodu, aby był bardziej przejrzysty i dokładny z powodu braku ograniczeń w JavaScript. TypeScript wymaga opisania danych, aby kompilator mógł sprawdzić kod i znaleźć błędy. Kompilator poinformuje Cię, jeśli używasz niedopasowanych typów, jeśli jesteś poza zasięgiem lub próbujesz zwrócić inny typ. Tak więc, gdy używasz zewnętrznych bibliotek i modułów z TypeScript, muszą one zawierać pliki opisujące typy w tym kodzie. Pliki te nazywane są plikami deklaracji typu z rozszerzeniem d.ts. Większość typów deklaracji dla modułów npm jest już napisanych i możesz je uwzględnić za pomocą npm install @types/module_name(gdzie nazwa_modułu to nazwa modułu, którego typy chcesz uwzględnić).

Istnieją jednak moduły, które nie mają definicji typów, i aby usunąć błąd i zaimportować moduł za pomocą import * as module_name from 'module-name', utwórz folder typingsw katalogu głównym projektu, w środku utwórz nowy folder z nazwą modułu i tym folder utwórz module_name.d.tsplik i zapisz declare module 'module_name'. Po to właśnie przejdź do tsconfig.jsonpliku i dodać "typeRoots": [ "../../typings", "../../node_modules/@types"]w compilerOptions(z właściwą ścieżkę względną do folderów), aby pozwolić maszynopis wie, gdzie można go znaleźć definicje typów bibliotek i modułów i dodać nową właściwość "exclude": ["../../node_modules", "../../typings"]do pliku. Oto przykład, jak powinien wyglądać plik tsconfig.json:

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

W ten sposób błąd zniknie i będziesz mógł trzymać się najnowszych reguł ES6 i TypeScript.

Marko Rochevski
źródło
Działa to tylko dla mnie, jeśli nazwałem plik pisma index.d.ts. Poza tym było to jedyne rozwiązanie, które zadziałało dla mnie.
Chris Haines
21

Dla każdego, kto to czyta, spróbuj zmienić nazwę pliku .js na .ts

Edycja: Możesz także dodać "allowJs": truedo pliku tsconfig.

Martin Lockett
źródło
tak, miałem ten sam problem z „wykresami reakcji-reakcji” i to rozwiązanie działało jak urok.
yawningphantom
16

Ten sposób działa dla mnie:

1. dodaj własną deklarację do pliku deklaracji, takiego jak index.d.ts (może w katalogu głównym projektu)
declare module 'Injector';
2. dodaj plik index.d.ts do pliku 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
    }

- edycja: potrzebne cudzysłowy wokół nazwy modułu

Lumaskcete
źródło
4

Miałem ten sam problem z użyciem modułu węzła z aplikacją reagującą napisaną na maszynie. Moduł został pomyślnie zainstalowany przy użyciu npm i --save my-module. Jest napisany javascript i eksportuje Clientklasę.

Z:

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

Kompilacja kończy się niepowodzeniem z błędem:

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-modulenie istnieje, więc dodałem my-module.d.tsplik obok tego, do którego my-modulejest importowany, z sugerowaną linią. Wtedy dostałem błąd:

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

Klient jest faktycznie eksportowany i działa normalnie, jeśli użyję go w aplikacji js. Ponadto poprzedni komunikat mówi mi, że kompilator szuka odpowiedniego pliku ( /node_modules/my-module/lib/index.jsjest zdefiniowany w my-module/package.json "main"elemencie).

Rozwiązałem problem, mówiąc kompilatorowi, że nie dbam o niejawne any, to znaczy ustawiłem falsenastępujący wiersz tsconfig.jsonpliku:

    "noImplicitAny": false,
Kanthavel
źródło
14
To znaczy, działa, ale tracisz możliwość ścisłego wpisywania reszty kodu. To nie jest świetne obejście.
phillyslick
3

prosty do naprawienia jest:

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

jeśli chcesz zadeklarować interfejs obiektu (Polecaj dla dużego projektu) możesz użyć:

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

Jak tego użyć? prosty..

const x = require('foo') // or import x from 'foo'
x.getName() // intellisense can read this
Abdul Aziz Al Basyir
źródło
2

Ja też to dostawałem, przez pewien czas byłem zdumiony, nawet gdy moduł i typy były już zainstalowane i kilkakrotnie ładowałem IDE.

W moim przypadku naprawiłem to, kończąc procesy terminalowe, usuwając node_modules, czyszcząc pamięć podręczną menedżera pakietów węzłów i robiąc nowe, installa następnie ponownie ładując edytor.

Lew
źródło
2

Niestety, nie jest w naszych rękach, czy twórca pakietu przeszkadza plikowi deklaracji. To, co zwykle robię, to taki plik, index.d.tsktóry będzie zawierał wszystkie brakujące pliki deklaracji z różnych pakietów:

Index.ts:

declare module 'v-tooltip';
declare module 'parse5';
declare module 'emoji-mart-vue-fast';
Luke Garrigan
źródło
0

To działało ode mnie.

npm install --save readline

honkskillet
źródło
0

Próbowałem już wszystkiego tutaj, ale dla mnie był to zupełnie inny problem: musiałem usunąć z moich *.d.tswszelkich instrukcji importu:

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

Po usunięciu błędu zniknął ...

Wyjaśnienie : Kiedy deklarujemy moduł w *.d.tspliku, jest on automatycznie wybierany przez kompilator Typescript jako moduł otoczenia (ten, którego nie trzeba jawnie importować). Gdy określimy import ... from ..., plik staje się teraz normalnym modułem (ES6), a zatem nie zostanie pobrany automatycznie. Dlatego jeśli nadal chcesz, aby zachowywał się jak moduł otoczenia , użyj innego stylu importu, takiego jak:

type MyType: import('3rd-party-module').SomeModuleType;
Ilyas Assainov
źródło
-4

Po prostu możesz go zaimportować, używając następującego kodu:

var _ = require('your_module_name');
Riyad Khalifeh
źródło