Pisanie modułów NPM w Typescript

103

Pracuję nad moim pierwszym modułem NPM. Krótko pracowałem wcześniej z maszynopisem i dużym problemem było to, że dla wielu modułów nie było dostępnych plików definicji. Pomyślałem więc, że dobrym pomysłem byłoby napisanie mojego modułu na maszynie.

Jednak nie mogę znaleźć żadnych informacji na temat najlepszego sposobu, aby to zrobić. Znalazłem to pokrewne pytanie „ Czy mogę napisać pakiet npm w coffeescript? ”, Gdzie ludzie sugerują publikowanie tylko plików javascript. Ale w przeciwieństwie do plików coffeescript, pliki maszynopisu mogą być w rzeczywistości przydatne, jeśli są używane w aplikacji do pisania na maszynie.

Czy powinienem dołączyć pliki Typescript podczas publikowania modułu NPM, czy też powinienem publikować tylko pliki javascript i udostępniać wygenerowane pliki .d.ts do DefinitelyTyped?

Andreas Gassmann
źródło
2
Przydatne uwagi: Napisałem projekt, copee , wraz z postem na blogu, aby przeprowadzić cię przez konfigurację projektu TS do emitowania definicji typów wraz z celami CJS i ESM przed opublikowaniem w npm. Pozwoli to zmaksymalizować użycie z node.js i przeglądarkami w przyszłości.
styfle

Odpowiedzi:

84

Oto przykładowy moduł Node napisany w TypeScript: https://github.com/basarat/ts-npm-module

Oto przykładowy projekt TypeScript korzystający z tego przykładowego modułu https://github.com/basarat/ts-npm-module-consume

Zasadniczo musisz:

  • kompiluj z commonjsideclaration:true
  • wygeneruj .d.tsplik

I wtedy

  • Niech twój ID przeczyta wygenerowany plik .d.ts.

Atom-TypeScript zapewnia po prostu ładny przepływ pracy wokół tego: https://github.com/TypeStrong/atom-typescript#packagejson-support

basarat
źródło
Należy zaktualizować łącze kotwicy Atom-TypeScript (kotwica jest już nieprawidłowa).
Fidan Hakaj
@basarat, w module ts-npm-module używasz "version": "1.5.0-alpha". Zakładam, że jest to wersja Typescript, z którą transpilujesz. Czy ma to znaczenie, aby to pominąć? (nie jest to wykonywane automatycznie przez wtyczkę Atom). Jeśli używana jest wersja, czy będzie to wymagało od innych użytkowników użycia dokładnej wersji do transpile (lub tylko nowszych)? (a może to wersja tsconfig.json?)
justin
Czy masz przypadek użycia z modułami zależnymi od innych bibliotek? Aby uniknąć problemu z podwójną definicją, musisz skonfigurować tsconfig.json, ale moim zdaniem wydaje się to zbyt ręczne.
Sérgio Michels
1
czy nadal byłby Pan zwolennikiem tego podejścia w czwartym kwartale 2016 roku?
SuperUberDuper
7
To był niezły poradnik
tsmean.com/articles/how-to-write-a-typescript-library
78

W przypadku języka TypeScript 3.x lub TypeScript 2.x poniższe kroki opisują, co należy zrobić, aby utworzyć bibliotekę (pakiet npm) z TypeScript:

  • Stwórz swój projekt tak jak zwykle (z testami i wszystkim)
  • Dodaj declaration: truedo, tsconfig.jsonaby wygenerować typy.
  • Wyeksportuj interfejs API za pomocą pliku index.ts
  • W sekcji package.jsonwskaż wygenerowane typy. Na przykład, jeśli outDirtak dist, dodaj "types": "dist/index.d.ts"do pakietu json.
  • W sekcji package.jsonwskaż swój główny plik wejściowy. Na przykład, jeśli Twój outDirjest, dista główny plik wejściowy to index.js, dodaj "main": "dist/index.js"do pliku package.json.
  • Utwórz, .npmignoreaby zignorować niepotrzebne pliki (np. Źródło).
  • Opublikuj w npm z npm publish. Użyj specyfikacji Semver do aktualizacji (poprawki / poprawki błędów npm version patch, nierozerwalne dodatki, zepsute npm version minorzmiany API npm version major)

Ponieważ zajęło mi trochę czasu, aby przejrzeć wszystkie przestarzałe zasoby na ten temat w Internecie (takie jak ten na tej stronie ...), postanowiłem zawrzeć to w bibliotece instrukcji pisania na maszynie aktualny działający minimalny przykład.

bersling
źródło
Czy będę musiał sprawdzić js w kontroli źródła? A może npm zachowuje własną wersję kodu?
Olian04
1
@ Olian04 Mówisz, że utwórz .npmignoreplik, aby powiedzieć npm, które pliki zignorować podczas publikowania ( .tspliki) i .gitignorepowiedzieć gitowi, które pliki mają ignorować ( dist/)
Purag
@ Olian04 nie, nie musisz (a IMO nie powinno) zatwierdzać wygenerowanego pliku / ów JS. Nie są one częścią źródła projektu.
Josh M.
59

To jest nowsza odpowiedź przy użyciu TypeScript 1.8.10:

Struktura mojego projektu to:

|
|--- src
|--- test
|--- dist     <= My gulp file compiles and places the js, sourcemaps and .d.ts files here
|      |--- src
|      |--- test
|--- typings
.gitignore
.npmignore
gulpfile.js
package.json
README.md
tsconfig.json
tslint.json
typings.json

Dodałem, co następuje, .npmignoreaby uniknąć dołączania zbędnych plików i zachować minimum niezbędne do zaimportowania i działania pakietu:

node_modules/
*.log
*.tgz

src/
test/
gulpfile.js
tsconfig.json
tslint.json
typings.json
typings
dist/test

Mój .gitignorema:

typings

# ignore .js.map files
*.js.map
*.js
dist

Mój package.jsonma:

"main": "dist/src/index.js",
"typings":  "dist/src/index.d.ts",

Teraz biegnę: npm pack

Wynikowy plik (po rozpakowaniu) ma następującą strukturę:

|
|--- dist
|       |--- src
|              |
|              index.js
|              index.js.map
|              index.d.ts
|
package.json
README.md

Teraz przechodzę do projektu, w którym chcę użyć tego jako biblioteki i wpisuję: npm install ./project-1.0.0.tgz

Pomyślnie instaluje się.

Teraz tworzę plik index.tsw moim projekcie, w którym właśnie zainstalowałem npm import Project = require("project");

Wpisywanie Project.daje mi opcje Intellisense, które były celem tego całego ćwiczenia.

Mam nadzieję, że pomoże to komuś innemu w używaniu projektów TypeScript npm jako bibliotek wewnętrznych w ich większych projektach.

PS: Uważam, że takie podejście kompilacji projektów do modułów npm, które można wykorzystać w innych projektach, przypomina te znane .dllna .NETświecie. Mogę dobrze wyobrazić sobie projekty organizowane w rozwiązaniu w kodzie VS, w którym każdy projekt tworzy pakiet npm, który można następnie wykorzystać w innym projekcie w rozwiązaniu jako zależność.

Ponieważ zajęło mi to sporo czasu, opublikowałem to na wypadek, gdyby ktoś tu utknął.

Opublikowałem go również w związku z zamkniętym błędem na: https://github.com/npm/npm/issues/11546


Ten przykład został przesłany do Github: vchatterji / tsc-seed

Varun Chatterji
źródło
czy możesz przesłać przykład na github? To by bardzo pomogło! :)
Han Che
3
Przykład został przesłany na Github: github.com/vchatterji/tsc-seed
Varun Chatterji
Jak można go również używać w projektach bez maszynopisu?
SuperUberDuper
5

Zamiast definicji typu należy opublikować oryginalne źródła maszynopisu. W package.jsonpozwolić „typów” wskaż obiekt do pliku * .TS.

*.d.ts dobrze jest dodawać adnotacje do istniejących bibliotek JS, ale jako konsument wolę czytać kod maszynopisu niż przełączać się między definicjami typów i wygenerowanym kodem JS o niższym poziomie.

Sven Efftinge
źródło
1
Jak dotąd wydaje się, że kompilator TypeScript nie nadaje się do tego. Zobacz ten numer github.com/Microsoft/TypeScript/issues/14479
Sven Efftinge
2
obecnie *.d.tsdołączanie jest zalecanym sposobem, ale zgadzam się z Tobą korzyści płynące z dołączania *.tsplików, typescriptlang.org/docs/handbook/declaration-files/…
Tim
5

Kieruję się głównie sugestią Varuna Chatterjiego

Chciałbym jednak pokazać kompletny przykład z testowaniem jednostkowym i pokryciem kodu oraz publikowaniem go npmi importowaniem przy użyciujavascript lubtypescript

Ten moduł jest napisany przy użyciu typescript 2.2i ważne jest, aby skonfigurować punkt prepublishzaczepienia do kompilowania kodu przy użyciutsc przed opublikowaniem go w npm

https://github.com/sweetim/haversine-position

https://www.npmjs.com/package/haversine-position

Tim
źródło
1
To bardzo przydatny przykład, dzięki za udostępnienie! Obecnie próbuję też opanować tworzenie paczek w ten sposób.
Jeffrey Westerkamp
1
Od lipca 2017 r. Jest to najlepsza struktura projektu, z jaką się zetknąłem. Podziękowania dla Tim i Varun Chatterji
adgang
3

Możesz użyć autodts do obsługi dystrybucji i używania .d.tsplików z npm również bez wsparcia ze strony Atom IDE.

autodts generatespakuje wszystkie twoje własne .d.tspliki razem do opublikowania na npm i autodts linkobsługuje odniesienia do innych zainstalowanych pakietów, które nie zawsze mogą znajdować się bezpośrednio pod node_modulesw większym projekcie podzielonym na kilka podpakietów.

Oba polecenia odczytu z ich ustawienia package.jsonoraz tsconfig.jsonw „Convention Over Configuration” stylu.

Jest jeszcze jedna odpowiedź na temat stackoverflow i post na blogu zawierający więcej szczegółów.

jjrv
źródło