Après avoir essayé des suggestions postées dans autres endroits , je ne parviens pas à faire exécuter un projet TypeScript utilisant un module NPM non typé. Vous trouverez ci-dessous un exemple minimal et les étapes que j'ai suivies.
Pour cet exemple minimal, nous allons prétendre que lodash
n'a pas de définition de type existante. En tant que tel, nous allons ignorer le paquet @types/lodash
et essayer d'ajouter manuellement son fichier de typage lodash.d.ts
à notre projet.
Structure de dossier
Ensuite, les fichiers.
Fichier foo.ts
///<reference path="../typings/custom/lodash.d.ts" />
import * as lodash from 'lodash';
console.log('Weeee');
Le fichier lodash.d.ts
est copié directement à partir du package @types/lodash
d'origine.
Fichier index.d.ts
/// <reference path="custom/lodash.d.ts" />
/// <reference path="globals/lodash/index.d.ts" />
Fichier 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"
}
Fichier 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"
]
}
Fichier typings.json
{
"name": "TestName",
"version": false,
"globalDependencies": {
"lodash": "file:typings/custom/lodash.d.ts"
}
}
Comme vous pouvez le constater, j'ai essayé de nombreuses manières d'importer des typages:
foo.ts
typings
dans package.json
typeRoots
dans tsconfig.json
avec un fichier typings/index.d.ts
types
explicite dans tsconfig.json
types
dans tsconfig.json
typings.json
et en exécutant typings install
Pourtant, quand je lance TypeScript:
E:\temp\ts>tsc
error TS2688: Cannot find type definition file for 'lodash'.
Qu'est-ce que je fais mal?
Malheureusement, ces éléments ne sont actuellement pas très bien documentés, mais même si vous parveniez à les faire fonctionner, examinons votre configuration afin de comprendre ce que fait chaque partie et en quoi elle est liée au traitement et au chargement des typages par TypeScript.
Voyons d'abord l'erreur que vous recevez:
error TS2688: Cannot find type definition file for 'lodash'.
En fait, cette erreur ne provient pas de vos importations, de vos références ou de votre tentative d’utiliser lodash n’importe où dans vos fichiers ts. Cela vient plutôt d'un malentendu sur la façon d'utiliser les propriétés typeRoots
et types
, aussi allons-y un peu plus en détail.
La chose à propos des propriétés typeRoots:[]
et types:[]
est qu’elles sont PAS des méthodes à usage général pour charger des fichiers de déclaration arbitraire (*.d.ts
).
Ces deux propriétés sont directement liées à la nouvelle fonctionnalité TS 2.0 qui permet de conditionner et de charger les déclarations de typage depuis packages NPM.
Il est très important de comprendre que ceux-ci ne fonctionnent qu'avec les dossiers au format NPM (c’est-à-dire un dossier contenant un package package.json ou index.d.ts ).
La valeur par défaut pour typeRoots
est:
{
"typeRoots" : ["node_modules/@types"]
}
Par défaut, cela signifie que TypeScript ira dans le dossier node_modules/@types
et essaiera de charger chaque sous-dossier trouvé sous forme de npm package.
Il est important de comprendre que cela échouera si un dossier n'a pas de structure semblable à un paquet npm.
C'est ce qui se passe dans votre cas et la source de votre erreur initiale.
Vous avez commuté typeRoot pour être:
{
"typeRoots" : ["./typings"]
}
Cela signifie que TypeScript va maintenant analyser le dossier ./typings
pour sous-dossiers et essayer de charger chaque sous-dossier trouvé en tant que module npm.
Faisons donc comme si vous veniez de disposer de la configuration typeRoots
pour qu'elle pointe sur ./typings
mais ne disposait pas encore de la configuration de la propriété types:[]
. Vous verriez probablement ces erreurs:
error TS2688: Cannot find type definition file for 'custom'.
error TS2688: Cannot find type definition file for 'global'.
En effet, tsc
analyse votre dossier ./typings
et recherche les sous-dossiers custom
et global
. Il essaie ensuite de les interpréter comme des types de paquets npm, mais il n'y a pas de index.d.ts
ou package.json
dans ces dossiers et vous obtenez donc l'erreur.
Parlons maintenant un peu de la propriété types: ['lodash']
que vous définissez. Qu'est-ce que cela fait? Par défaut, TypeScript chargera tous les sous-dossiers trouvés dans votre typeRoots
. Si vous spécifiez une propriété types:
, il ne chargera que ces sous-dossiers spécifiques.
Dans votre cas, vous lui dites de charger le dossier ./typings/lodash
mais il n’existe pas. C'est pourquoi vous obtenez:
error TS2688: Cannot find type definition file for 'lodash'
Résumons donc ce que nous avons appris. TypeScript 2.0 a introduit typeRoots
et types
pour le chargement de fichiers de déclaration conditionnés dans des packages npm . Si vous avez des saisies personnalisées ou des fichiers d.ts
uniques en vrac qui ne sont pas contenus dans un dossier, conformément aux conventions de package npm, ces deux nouvelles propriétés ne sont pas ce que vous voulez utiliser. TypeScript 2.0 ne change pas vraiment la manière dont ces ressources seraient consommées. Il vous suffit d'inclure ces fichiers dans votre contexte de compilation de l'une des nombreuses manières habituelles:
L'inclure directement dans un fichier .ts
: ///<reference path="../typings/custom/lodash.d.ts" />
Inclure ./typings/custom/lodash.d.ts
dans votre propriété files: []
.
Inclure ./typings/index.d.ts
dans votre propriété files: []
(qui inclut alors de manière récursive les autres saisies.
Ajout de ./typings/**
à votre includes:
Espérons que, sur la base de cette discussion, vous serez en mesure de dire pourquoi les changements que vous avez rendus fous à votre tsconfig.json
ont permis de faire fonctionner les choses à nouveau.
Une chose que j’ai oublié de mentionner est que les propriétés typeRoots
et types
ne sont vraiment utiles que pour le chargement automatique de déclarations globales.
Par exemple si vous
npm install @types/jquery
Et vous utilisez le tsconfig par défaut, alors ce paquetage de types jquery sera chargé automatiquement et $
sera disponible dans tous vos scripts sans avoir à faire plus de ///<reference/>
ou import
La propriété typeRoots:[]
est destinée à ajouter des emplacements supplémentaires à partir desquels les packages de type seront chargés automatiquement.
Le principal cas d'utilisation de la propriété types:[]
consiste à désactiver le comportement de chargement automatique (en le définissant sur un tableau vide), puis à répertorier uniquement les types spécifiques que vous souhaitez inclure globalement.
L'autre façon de charger des packages de types à partir des divers typeRoots
consiste à utiliser la nouvelle directive ///<reference types="jquery" />
. Notez le types
au lieu de path
. Encore une fois, cela n’est utile que pour les fichiers de déclaration globaux, généralement ceux qui ne font pas import/export
.
Maintenant, voici l'une des choses qui crée une confusion avec typeRoots
. Rappelez-vous, j'ai dit que typeRoots
concerne l'inclusion globale de modules. Mais @types/folder
est également impliqué dans la résolution de module standard (quel que soit votre réglage typeRoots
).
Plus précisément, l’importation explicite des modules contourne toujours toutes les options includes
, excludes
, files
, typeRoots
et types
. Alors quand tu fais:
import {MyType} from 'my-module';
Toutes les propriétés mentionnées ci-dessus sont complètement ignorées. Les propriétés pertinentes pendant résolution du module sont baseUrl
, paths
et moduleResolution
.
Fondamentalement, lorsque vous utilisez la résolution de module node
, il commence à rechercher un nom de fichier my-module.ts
, my-module.tsx
, my-module.d.ts
à partir du dossier désigné par votre baseUrl
. configuration.
S'il ne trouve pas le fichier, il recherchera un dossier nommé my-module
, puis recherchera un package.json
avec une propriété typings
, s'il y a package.json
ou Aucune propriété _ typings
à l'intérieur ne lui indiquant le fichier à charger, elle recherchera ensuite index.ts/tsx/d.ts
dans ce dossier.
Si cela ne réussit toujours pas, il recherchera ces mêmes choses dans le dossier node_modules
à partir de votre baseUrl/node_modules
.
De plus, s'il ne les trouve pas, il recherchera baseUrl/node_modules/@types
pour les mêmes choses.
S'il n'a toujours rien trouvé, il commencera par aller dans le répertoire parent et recherchera node_modules
et node_modules/@types
. Il continuera à monter dans les répertoires jusqu'à ce qu'il atteigne la racine de votre système de fichiers (même en obtenant des modules de nœuds en dehors de votre projet).
Une chose que je tiens à souligner est que la résolution du module ignore complètement tout typeRoots
que vous définissez. Donc, si vous avez configuré typeRoots: ["./my-types"]
, la recherche ne sera pas effectuée pendant la résolution explicite du module. Il ne sert que de dossier dans lequel vous pouvez mettre les fichiers de définition globale que vous souhaitez mettre à la disposition de l’application entière sans avoir besoin d’importer ou de faire référence.
Enfin, vous pouvez remplacer le comportement du module par des mappages de chemin (c'est-à-dire la propriété paths
.). Ainsi, par exemple, j'ai mentionné que toute typeRoots
personnalisée n'est pas consultée lors de la tentative de résolution d'un module. Mais si vous avez aimé, vous pouvez résoudre ce problème de la manière suivante:
"paths" :{
"*": ["my-custom-types/*", "*"]
}
Essayez de modifier l’importation comme indiqué dans le côté droit avant de l’inclure (le *
à droite représente votre chaîne d’importation initiale. Par exemple, si vous importez:
import {MyType} from 'my-types';
Il essaiera d’abord l’import comme si vous aviez écrit:
import {MyType} from 'my-custom-types/my-types'
Et puis, s'il ne le trouve pas, il essaiera de nouveau sans le préfixe (le deuxième élément du tableau est simplement *
, ce qui signifie l'importation initiale.
Vous pouvez ainsi ajouter des dossiers supplémentaires pour rechercher des fichiers de déclaration personnalisés ou même des modules .ts
personnalisés que vous souhaitez pouvoir utiliser import
.
Vous pouvez également créer des mappages personnalisés pour des modules spécifiques:
"paths" :{
"*": ["my-types", "some/custom/folder/location/my-awesome-types-file"]
}
Cela te laisserait faire
import {MyType} from 'my-types';
Mais alors lisez ces types de some/custom/folder/location/my-awesome-types-file.d.ts
Edit: obsolète. Lisez la réponse ci-dessus.
Je ne comprends toujours pas cela, mais j'ai trouvé une solution. Utilisez le tsconfig.json
suivant:
{
"compilerOptions": {
"target": "ES6",
"jsx": "react",
"module": "commonjs",
"sourceMap": true,
"noImplicitAny": true,
"experimentalDecorators": true,
"baseUrl": ".",
"paths": {
"*": [
"./typings/*"
]
}
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
Supprimez typings.json
et tout ce qui se trouve dans le dossier typings
sauf lodash.d.ts
. Supprimez également toutes les références ///...
"*": ["./types/*"]
Cette ligne dans les chemins tsconfig a tout corrigé après 2 heures de lutte.
{
"compilerOptions": {
"moduleResolution": "node",
"strict": true,
"baseUrl": ".",
"paths": {
"*": ["./types/*"]
},
"jsx": "react",
"types": ["node", "jest"]
},
"include": [
"client/**/*",
"packages/**/*"
],
"exclude": [
"node_modules/**/*"
]
}
types est le nom du dossier situé à côté de node_module, c'est-à-dire au niveau du client dossier (ou src dossier) types/third-party-lib/index.d.ts
index.d.ts a declare module 'third-party-lib';
Note: La configuration ci-dessus est une configuration incomplète, juste pour donner une idée de son apparence avec les types, les chemins, les inclure et les exclure.