Jak konsumować moduły npm z maszynopisu?

91

Daję szansę na maszynopis. Działa dobrze na scenie Hello world. Teraz próbuję użyć modułu npm:

index.ts =

import _ = require('lodash')

console.log(_.toUpper('Hello, world !'))

To nie działa:

  • tsc index.ts -> Cannot find module 'lodash'. (2307)
  • node-ts index.js -> Cannot find module 'lodash'. (2307)

Przeglądanie dokumentacji maszynopisu i Google nie pomogło. Inne pytania S / O pozostają bez odpowiedzi ( tutaj i tutaj ) lub niezwiązane.

Elementy :

  • maszynopis 1.8 najnowszy
  • Tak, lodash jest zainstalowany npm i --save lodashi istnieje w moim systemie plików (zaznaczone)
  • Ja też typings i --save lodash
  • warianty import * as _ from 'lodash'lub const _ = require('lodash')też nie działają
  • Próbowałem ulepszyć opcje tsconfig.json, jak sugerowano w innych odpowiedziach "moduleResolution": "node"i "module": "commonjs"jak sugerowano w niektórych odpowiedziach, nadal nie działa

Jak konsumujemy pakiet npm w maszynie?

Offirmo
źródło
2
Czy dodałeś odniesienie do lodash.d.ts w swoim index.ts? Powinien wyglądać podobnie do tego: ///<reference path="../typings/lodash/lodash.d.ts"/>
Granga
@Granga To działa. Czy możesz dodać to jako odpowiedź?
Offirmo
2
Cieszę się, że działa. Blackus już dodał odpowiedź i jeszcze lepiej precyzuje to, co zasugerowałem. Jedna uwaga: gdy pliki wejściowe są określone w wierszu poleceń (tak jest w twoim przypadku), pliki tsconfig.json są ignorowane. ( źródło )
Granga

Odpowiedzi:

61

[EDYCJA] Wielkie dzięki za tę odpowiedź! Jednak od 2018 roku jest nieaktualny. Czytelnicy, spójrz na inne odpowiedzi.

Istnieje kilka sposobów importowania modułów z npm. Ale jeśli nie dostaniesz wpisów, tsczawsze będzie narzekać, że nie może znaleźć modułu, którego potrzebujesz (nawet jeśli transpiled js faktycznie działa).

  • Jeśli masz pisma i nie używasz tsconfig.json, użyj, referenceaby zaimportować typy:

    /// <reference path="path/to/typings/typings.d.ts" />
    
    import * as _ from 'lodash`;
    
    console.log(_.toUpper('Hello, world !'))
    
  • Jeśli używasz tsconfig.jsonpliku, upewnij się, że dołączony jest plik z typami (lub nie jest wykluczony, Twój wybór) i postępuj importpodobnie jak w poprzednim przykładzie.

W przypadku, gdy nie ma dostępnych typów. Masz dwie możliwości: napisać własną w .d.tspliku lub zignorować sprawdzanie typów w bibliotece.

Aby całkowicie zignorować sprawdzanie typu (nie jest to zalecany sposób), zaimportuj bibliotekę do zmiennej typu any.

 const _: any = require('lodash');

 console.log(_.toUpper('Hello, world !'))

tscbędzie narzekać, że requirenie istnieje. Podaj nodetypy lub declare, aby odrzucić błąd.

Blackus
źródło
2
Pełna odpowiedź z 3 rozwiązaniami. +1
Offirmo,
Dodatek: działa nawet ts-nodetak długo, jak przywoływany jest indeks tsconfig.json
typów
Jestem zdezorientowany tym, co masz na myśli mówiąc „zadeklaruj to, aby odrzucić błąd”. Czy muszę wprowadzić tę zmianę w module, który próbuję zaimportować?
Slug
1
Ta odpowiedź jest bardzo nieaktualna. Zobacz moją nową odpowiedź poniżej stackoverflow.com/a/53786892/587407
Offirmo,
50

[2018/12] Nowa, aktualna odpowiedź na to pytanie, które zadałem w 2016 roku, która mimo posiadania nieaktualnych odpowiedzi wciąż wykazuje dużą aktywność.

Krótko mówiąc, TypeScript wymaga informacji o typie o kodzie twojego pakietu (aka „ pliki deklaracji typu ” aka „typowania”) i słusznie mówi ci, że w przeciwnym razie straciłbyś cały sens TypeScript. Istnieje kilka rozwiązań umożliwiających ich udostępnianie lub rezygnację z nich, wymienionych tutaj w kolejności najlepszych praktyk:


Rozwiązanie 0 : moduł już zapewnia wpisywanie. Jeśli jego package.json zawiera taką linię:

"typings": "dist/index.d.ts",

jest już z obsługą TypeScript. Najprawdopodobniej tak nie jest, jeśli czytasz tę stronę, więc kontynuujmy ...


Rozwiązanie 1 : skorzystaj z napisów wniesionych przez społeczność z DefinitelyTyped . W przypadku modułu „foo” spróbuj tego:

npm add -D @types/foo

jeśli to zadziała, jackpot! Masz teraz wpisy i możesz używać swojego modułu. Jeśli npm narzeka, że ​​nie może znaleźć modułu @ types / foo, kontynuujmy ...


Rozwiązanie 2 : podaj niestandardowe wpisy dotyczące tego modułu. (z opcją zerowego wysiłku)

  1. Utwórz folder o nazwie „typings-custom” w katalogu głównym projektu
  2. Odwołaj się do zawartości tego folderu w pliku tsconfig.json:
"include": [
    "./typings-custom/**/*.ts"
]
  1. Utwórz plik o dokładnej nazwie: foo.d.ts [foo = nazwa modułu] z zawartością:
declare module 'foo'

Twój kod TypeScript powinien teraz zostać skompilowany, aczkolwiek BEZ informacji o typie (TypeScript rozważa moduł foo typu „any”).

Możesz także spróbować samodzielnie wpisać informacje o typie, przeglądając oficjalny dokument i / lub przykłady z DefinitelyTyped . Jeśli tak, pomyśl o dodaniu swoich wpisów bezpośrednio do modułu (rozwiązanie 0, jeśli autor modułu akceptuje) lub do DefinitelyTyped (rozwiązanie 1)

Offirmo
źródło
1
@Offirmo, możemy również zadeklarować wiele niestandardowych wpisów w jednym pliku! Więc nie potrzeba wielu plików (może?).
lazycipher
Krok 2. Reference the content of this folder in your tsconfig.json:daje następujący błąd: Unknown compiler option 'include'.
Sumit
1
@Sumit to nie jest opcja kompilatora, powinna być rodzeństwemcompilerOptions
Offirmo.
22

Prawdopodobnie brakuje Ci plików deklaracji .

Aby uzyskać więcej informacji, zobacz DefinitelyTyped .


Spróbuj tego:

npm install --save lodash
npm install --save @types/lodash

Teraz możesz importować.

import _ from 'lodash';

Jeśli importowany moduł ma wiele eksportów , możesz to zrobić:

import { Express, Router } from 'express';

Jeśli moduł, który importujesz, „nie ma domyślnego eksportu” , musisz to zrobić:

import * as http from 'http';
Derek Soike
źródło
Dlaczego musimy używać, * as _a nie tak _ from 'lodash'jak w kodzie ES6?
JohnnyQ
@JohnnyQ Słuszna uwaga. import _ from 'lodash';W tym przypadku użycie jest lepsze. Zaktualizowałem moją odpowiedź, aby pokazać różne sposoby importowania i dlaczego ich używasz.
Derek Soike
1
Jest * as _ to potrzebne, jeśli moduł nie ma domyślnego eksportu. Kompilator tsc ostrzeże o tym.
user2867342
Czy określenie „brak domyślnego eksportu” oznacza brak zdefiniowanych typów maszynopisów (tj. Importowanie zwykłego modułu JavaScript)? Jestem nowy w JS / Typescript ....
Big Rich
2
@BigRich „Brak domyślnego eksportu” oznacza, że ​​moduł nie zawiera export default <...>instrukcji. Zapoznaj się z sekcją „Domyślne eksportowanie” w dokumentacji modułów maszynopisu .
Derek Soike
4

U mnie to zadziałało.

  1. Utwórz folder o nazwie „typings”.
  2. W folderze typings utwórz nazwę pliku nazwa -modułu.d.ts . Zawiera:

    declare module "module-name";

  3. W tsconfig.json przejdź do folderu

    "typeRoots": [ "./typings", "../node_modules/@types" ]

Quynh Ngo
źródło
Cześć! Dzięki za wkład. Ta metoda jest już zawarta w mojej odpowiedzi i powinna być stosowana tylko w ostateczności.
Offirmo
Krok 3 In tsconfig.json, refer to the folderUnknown compiler option 'typesRoots'.
:,
1
@Sumit w moim przypadku „typesRoots” znajduje się w „compilerOptions”
Quynh Ngo
1
Jest to typeRoots, a nie typesRoots i powinno znajdować się w compilerOptions
CM
0

Otrzymuję ten błąd i żadna z odpowiedzi nie działała dla mnie, ale wymyślam coś, gdy chcesz pracować z modułem węzła w maszynie, zainstaluj je jako

$npm install @types/<module_name>

na przykład

npm install @types/cheerio

zamiast mówić

npm install cheerio
Crispen Gari
źródło