TypeScript 2: türlenmemiş npm modülü için özel tipler


93

İçinde yayınlanan önerileri denedikten sonra Başka yerlerde , kendimi türlenmemiş bir NPM modülü kullanan çalışan bir typcript projesi alamıyorum. Aşağıda minimal bir örnek ve denediğim adımlar bulunmaktadır.

Bu minimal örnek için, lodashmevcut tip tanımlarına sahip olmadığını varsayacağız. Bu nedenle, paketi görmezden geleceğiz @types/lodashve yazım dosyasını lodash.d.tsprojemize manuel olarak eklemeye çalışacağız .

Klasör yapısı

  • node_modules
    • Lodash
  • src
    • foo.ts
  • daktilo
    • özel
      • lodash.d.ts
    • küresel
    • index.d.ts
  • package.json
  • tsconfig.json
  • typings.json

Sonra dosyalar.

Dosya foo.ts

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

console.log('Weeee');

Dosya lodash.d.tsdoğrudan orijinal @types/lodashpaketinden kopyalanır .

Dosya index.d.ts

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

Dosya 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"
}

Dosya 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"
  ]
}

Dosya typings.json

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

Gördüğünüz gibi, yazımları içe aktarmanın birçok farklı yolunu denedim:

  1. Doğrudan içeri aktararak foo.ts
  2. İçindeki bir typingsmülk tarafındanpackage.json
  3. Kullanarak typeRootsiçinde tsconfig.jsonbir dosya iletypings/index.d.ts
  4. Açık bir typesgiriş kullanaraktsconfig.json
  5. Dahil ederek typesdizini içindetsconfig.json
  6. Özel bir typings.jsondosya oluşturup çalıştıraraktypings install

Yine de Typescript'i çalıştırdığımda:

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

Neyi yanlış yapıyorum?

Yanıtlar:


210

Maalesef bu şeyler şu anda çok iyi belgelenmemiştir, ancak çalıştırmayı başardıysanız bile, yapılandırmanızı gözden geçirelim, böylece her bir parçanın ne yaptığını ve yazımları nasıl işlediğini ve yüklediğini anlayabilirsiniz.

Öncelikle, aldığınız hatanın üzerinden geçelim:

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

Bu hata aslında içe aktarmalarınızdan veya referanslarınızdan veya ts dosyalarınızın herhangi bir yerinde lodash kullanma girişiminizden kaynaklanmamaktadır. Daha ziyade, typeRootsve typesözelliklerinin nasıl kullanılacağına dair bir yanlış anlaşılmadan kaynaklanıyor , bu yüzden bunlar hakkında biraz daha ayrıntıya girelim.

typeRoots:[]Ve types:[]özellikleriyle ilgili olan şey , bunların rasgele bildirim ( ) dosyalarını yüklemenin genel amaçlı yolları OLMAMASIDIR*.d.ts .

Bu iki özellik, NPM paketlerinden paketleme ve yükleme tipleme bildirimlerine izin veren yeni TS 2.0 özelliği ile doğrudan ilişkilidir .

Bunların sadece NPM formatındaki klasörlerle (yani bir package.json veya index.d.ts içeren bir klasör) ile çalıştığını anlamak çok önemlidir .

Varsayılan değer typeRoots:

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

Varsayılan olarak bu, typcript'innode_modules/@types klasöre gideceği ve orada bulduğu her alt klasörü npm paketi olarak yüklemeye çalışacağı anlamına gelir .

Bir klasör npm paketi benzeri bir yapıya sahip değilse bunun başarısız olacağını anlamak önemlidir.

Bu, sizin durumunuzda olan ve ilk hatanızın kaynağıdır.

TypeRoot'u şu şekilde değiştirdiniz:

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

Bu, typcript'in artık ./typingsklasörü alt klasörler için tarayacağı ve bulduğu her alt klasörü npm modülü olarak yüklemeye çalışacağı anlamına gelir .

Öyleyse, sadece typeRootsişaret etmek için bir kurulumunuz olduğunu, ./typingsancak henüz herhangi bir types:[]mülk kurulumunuz olmadığını varsayalım. Muhtemelen şu hataları görürsünüz:

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

Bunun nedeni tsc, ./typingsklasörünüzü taramak ve alt klasörleri customve global. Daha sonra bunları npm paket türü yazarak yorumlamaya çalışıyor, ancak bu klasörlerde index.d.tsya da yok package.jsonve bu nedenle hatayı alıyorsunuz.

Şimdi types: ['lodash']ayarladığınız mülk hakkında biraz konuşalım . Bu ne yapar? Varsayılan olarak, typcript, içinde bulduğu tüm alt klasörleri yükleyecektir typeRoots. Bir belirtirseniztypes: özellik , yalnızca bu belirli alt klasörleri yükleyecektir.

Sizin durumunuzda, ./typings/lodashklasörü yüklemesini söylüyorsunuz, ancak mevcut değil. Bu yüzden şunları elde edersiniz:

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

Öyleyse öğrendiklerimizi özetleyelim. Typescript 2.0 tanıtıldı typeRootsve npm paketlerindetypes paketlenmiş bildirim dosyalarını yüklemek için . Npm paketi kurallarını izleyen bir klasörde bulunmayan özel yazılarınız veya tek bir gevşek dosyalarınız varsa, bu iki yeni özellik kullanmak istediğiniz şey değildir. Typecript 2.0, bunların nasıl tüketileceğini gerçekten değiştirmez. Bu dosyaları birçok standart yoldan biriyle derleme bağlamınıza dahil etmeniz yeterlidir:d.ts

  1. Doğrudan bir .tsdosyaya dahil etme : ///<reference path="../typings/custom/lodash.d.ts" />

  2. Dahil ./typings/custom/lodash.d.tssizin de files: []mülk.

  3. Mülkünüze dahil ./typings/index.d.tsetme files: [](daha sonra yinelemeli olarak diğer türleri içerir.

  4. Ekleme ./typings/**için seninincludes:

Umarım, bu tartışmaya dayanarak, tsconfig.jsonyaptığınız şeylere neden kızdırdığınız değişikliklerin tekrar işe yaradığını söyleyebileceksiniz .

DÜZENLE:

Ben söz unuttuğunu bir şey olduğunu typeRootsve typesmülkiyet gerçekten sadece yararlıdır otomatik küresel beyanlarına yüklenmesi.

Örneğin eğer

npm install @types/jquery

Ve Jquery türleri paket otomatik yüklenecektir o, varsayılan tsconfig kullanıyor ve $başka yapmak zorunda wihtout tüm komut satışa sunulacak ///<reference/>ya daimport

typeRoots:[]Mülkiyet tipi nereden Başka yerler eklemek anlamına gelir paketleri otomatik ettirmesi yüklenecektir.

types:[]Tesisin birincil kullanım-case (boş bir diziye ayarlayarak) otomatik yükleme davranışı devre dışı bırakmaktır ve sonra sadece küresel dahil etmek istediğiniz belirli türlerini listeler.

Çeşitli paketlerden tür paketleri yüklemenin diğer yolu typeRoots, yeni ///<reference types="jquery" />yönergeyi kullanmaktır . typesBunun yerine dikkat edin path. Yine, bu yalnızca genel bildirim dosyaları için kullanışlıdır, genellikle işe yaramayan dosyalar import/export.

Şimdi, işte kafa karışıklığına neden olan şeylerden biri typeRoots. Unutmayın, bunun typeRootsmodüllerin küresel olarak dahil edilmesiyle ilgili olduğunu söylemiştim . Ama @types/folderaynı zamanda standart modül çözünürlüğünde de yer alır ( typeRootsayarınız ne olursa olsun ).

Özellikle, açıkça ithal modülleri her zaman tüm atlar includes, excludes, files, typeRootsve typesseçenekleri. Yani yaptığınızda:

import {MyType} from 'my-module';

Yukarıda belirtilen tüm özellikler tamamen göz ardı edilmiştir. Sırasında ilgili özellikler modül çözünürlüğü vardır baseUrl, pathsve moduleResolution.

Kullanırken Temel olarak, nodemodül çözünürlüğü, bir dosya adı arama başlayacaktır my-module.ts, my-module.tsx, my-module.d.tsklasörün başlayarak sizin tarafından işaret baseUrlyapılandırması.

Dosyayı bulamazsa, adlandırılmış bir klasör my-modulearayacak ve sonra package.jsonbir typingsözelliği olan bir özelliği arayacaktır , içinde hangi dosyanın yükleneceğini söyleyen özellik varsa package.jsonveya yoksa o klasör içinde typingsarayacaktır index.ts/tsx/d.ts.

Hala başarılı olmazsa, bu aynı şeyleri node_modulesklasörünüzden başlayarak arayacaktır baseUrl/node_modules.

Ayrıca bunları bulamazsa baseUrl/node_modules/@types, aynı şeyleri arayacaktır .

Hala bir şey bulamadıysa, ana dizine gitmeye node_modulesve node_modules/@typesorada aramaya başlayacaktır . Dosya sisteminizin köküne ulaşıncaya kadar dizinlerde yukarı çıkmaya devam edecektir (hatta projenizin dışındaki düğüm modüllerini bile alacaktır).

Vurgulamak istediğim bir şey, modül çözünürlüğünün typeRootsayarladığınız her şeyi tamamen yok saymasıdır . Yani yapılandırdıysanız typeRoots: ["./my-types"], bu, açık modül çözümlemesi sırasında aranmayacaktır. Yalnızca, daha fazla içe aktarmaya veya referans göstermeye gerek kalmadan tüm uygulama için kullanılabilir hale getirmek istediğiniz global tanım dosyalarını koyabileceğiniz bir klasör görevi görür.

Son olarak, modül davranışını yol eşlemeleriyle (yani pathsözellik) geçersiz kılabilirsiniz . Örneğin, typeRootsbir modülü çözmeye çalışırken herhangi bir geleneğe danışılmadığından bahsetmiştim . Ancak hoşunuza gittiyse, bu davranışı şu şekilde gerçekleştirebilirsiniz:

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

Bunun yaptığı şey, sol tarafla eşleşen tüm içe aktarmalar için, içe aktarmayı dahil etmeye çalışmadan önce sağ taraftaki gibi değiştirmeyi deneyin ( *sağ taraf, ilk içe aktarma dizenizi temsil eder. Örneğin, içe aktarırsanız:

import {MyType} from 'my-types';

Önce, yazmışsınız gibi içe aktarmayı deneyecektir:

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

Ve sonra bulamazsa, önekle tekrar deneyecekti (dizideki ikinci öğe sadece *ilk içe aktarma anlamına geliyor.

Bu şekilde, özel bildirim dosyalarını ve hatta .tsyapabilmek istediğiniz özel modülleri aramak için ek klasörler ekleyebilirsiniz import.

Ayrıca belirli modüller için özel eşlemeler de oluşturabilirsiniz:

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

Bu yapmana izin verirdi

import {MyType} from 'my-types';

Ama sonra bu türleri buradan okuyun some/custom/folder/location/my-awesome-types-file.d.ts


1
Detaylı cevabınız için teşekkürler. Çözümlerin tek başına çalıştığı, ancak iyi karışmadığı ortaya çıktı. İşleri açıklığa kavuşturuyor, bu yüzden size ödülü vereceğim. Birkaç noktayı daha cevaplamak için zaman bulabilirseniz, bu diğer insanlar için gerçekten yararlı olabilir. (1) typeRoots'un yalnızca belirli bir klasör yapısını kabul etmesi için bir neden var mı? Keyfi görünüyor. (2) typeRoots'u değiştirirsem, typcript, spesifikasyonun aksine node_modules'deki @types klasörlerini içerir. (3) Yazı yazma amacı açısından nedir pathsve nasıl farklıdır include?
Jodiug

1
Cevabı düzenledim, başka sorunuz olursa bana bildirin.
dtabuenc

1
Teşekkür ederim, geri kalanını okudum ve vay canına. Tüm bunları bulduğunuz için size yardımcı oluyor. Görünüşe göre burada iş yerinde gereksiz yere karmaşık birçok davranış var. Umarım Typescript, gelecekte yapılandırma özelliklerini biraz daha kendi kendini belgeleyen hale getirir.
Jodiug


2
Son örnek şöyle olmamalı mı "paths" :{ "my-types": ["some/custom/folder/location/my-awesome-types-file"] }?
Koen.

6

Düzenleme: güncel değil. Yukarıdaki cevabı okuyun.

Hala anlamıyorum ama bir çözüm buldum. Aşağıdakileri kullanın 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"
  ]
}

Kaldır typings.jsonve typingshariç klasör altındaki her şey lodash.d.ts. Ayrıca tüm ///...referansları kaldırın


3

"*": ["./types/*"] Tsconfig yollarındaki bu satır, 2 saatlik mücadeleden sonra her şeyi düzeltti.

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

türler , node_module'un yanında, yani istemci klasörü (veya src klasörü) types/third-party-lib/index.d.ts
düzeyinde bulunan klasör adıdır. index.d.ts vardırdeclare module 'third-party-lib';

Not: Yukarıdaki yapılandırma tamamlanmamış bir yapılandırmadır, sadece türler, yollar, dahil etme ve dışlama ile nasıl göründüğüne dair bir fikir vermek için.


2

Bunun eski bir soru olduğunu biliyorum, ancak daktilo araçları sürekli olarak değişiyor. Bu noktada en iyi seçeneğin tsconfig.json'daki "include" yol ayarlarına bağlı olduğunu düşünüyorum.

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

Varsayılan olarak, belirli değişiklikler yapmadığınız sürece, altındaki tüm * .ts ve tüm * .d.ts dosyaları src/otomatik olarak dahil edilecektir. Bence bu, özel tür bildirim dosyalarını özelleştirmeden eklemenin en kolay / en iyi yolu typeRootsvetypes .

Referans:

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.