web-dev-qa-db-fra.com

TypeScript 2: typages personnalisés pour le module npm non typé

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

  • node_modules
    • lodash
  • src
    • foo.ts
  • dactylographie
    • douane
      • lodash.d.ts
    • global
    • index.d.ts
  • package.json
  • tsconfig.json
  • typings.json

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:

  1. En l'important directement dans foo.ts
  2. Par une propriété typings dans package.json
  3. En utilisant typeRoots dans tsconfig.json avec un fichier typings/index.d.ts
  4. En utilisant un types explicite dans tsconfig.json
  5. En incluant le répertoire types dans tsconfig.json
  6. En créant un fichier personnalisé 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?

81
Jodiug

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:

  1. L'inclure directement dans un fichier .ts: ///<reference path="../typings/custom/lodash.d.ts" />

  2. Inclure ./typings/custom/lodash.d.ts dans votre propriété files: [].

  3. Inclure ./typings/index.d.ts dans votre propriété files: [] (qui inclut alors de manière récursive les autres saisies.

  4. 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.

MODIFIER:

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

175
dtabuenc

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 ///...

6
Jodiug

"*": ["./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.

2
Uday Sravan K