TypeScript - 3/3 : Installation & Migration
Suite de la deuxième partie du dossier.
Installation
npm install -g typescript
Le paquet typescript contient le compilateur tsc
découvert dans la première partie du dossier.
L’installation du paquet tslint est aussi conseillée (globale, ou locale à votre projet).
Dans le répertoire du projet, sont requis (recommandés) :
- Un fichier
tsconfig.json
, généré avec la commandetsc --init
ou récupéré d’un projet type boilerplate. - Un fichier
tslint.json
, généré avec la commandetslint --init
ou récupéré d’un projet type boilerplate. Pour ”linter” le projet, on exécutetslint -p .
à la racine du projet.
💡
-p
indique l’emplacement detsconfig.json
(détails)
- Un éditeur de code avec un support décent de TypeScript : VSCode, WebStorm, …
Intégration
Frontend
Il existe des configurations/plugins pour les principaux outils de transpilation et packaging:
- Avec Babel 7 et le preset babel-preset-typescript
- Avec Webpack et ts-loader ou awesome-typescript-loader; d’avantage d’informations dans la documentation officielle
- Avec Rollup et rollup-plugin-typescript2
- Pour Browserify, Grunt, Gulp, référez-vous à la documentation officielle
Backend et scripts
ts-node accélère légèrement le processus de développement, en permettant à node de charger des modules TypeScript (transpilés en mémoire lors de l’import).
Il peut être utilisé en ligne de commande, pour exécuter directement des fichiers TypeScript :
ts-node index.ts
ou bien exécuté comme module, dans un point d’entrée JavaScript classique (node index.js
) :
require('ts-node').register();
// on peut ensuite importer un fichier TypeScript (./src/index.ts)
require('./src/index');
Migration
L’intégration progressive de TypeScript dans un projet JavaScript existant est un bon exercice pour adopter le langage.
Adapter le code existant
- Activer
allowJs
(tsconfig.json
) afin que le code existant soit intégré au code généré partsc
. - Procéder à la modification du code, fichier par fichier, à l’aide de l’annotation
// @ts-check
.
@ts-check
tsc
effectue l’analyse statique du code JavaScript contenant le commentaire // @ts-check
.
Il est aussi possible d’utiliser l’option --checkJs
(CLI de tsc
, ou dans tsconfig.json
) pour analyser tous les fichiers JavaScript passés en entrée.
💡 Si vous optez pour
checkJs
, utilisez@ts-nocheck
pour exclure certains fichiers JavaScript de l’analyse. Pour exclure seulement certaines lignes de code, utilisez@ts-ignore
(avant chaque ligne).
Mieux encore : TypeScript peut aussi utiliser votre JSDoc pour trouver des erreurs dans votre code.
Voici un exemple, normalize-name.js
:
// @ts-check
/**
* @param {string} name Name to be normalized
*
* @return {string} Normalized name.
*/
function normalizeName(name) {
return name.trim().toUpperCase();
}
// Erreur : 5 n'est pas une string
normalizeName(5);
// Erreur : normalizeName retourne une string (calcul impossible)
const a = 3 * normalizeName('MiKe');
À la compilation tsc
renvoie les erreurs suivantes :
❌ normalize-name.js(13,15): error TS2345: Argument of type ‘5’ is not assignable to parameter of type ‘string’.
❌ normalize-name.js(15,15): error TS2363: The right-hand side of an arithmetic operation must be of type ‘any’, ‘number’ or an enum type.
Par contre, dans le code ci-dessus, passer undefined
à normalizeName
n’est pas signalé comme une erreur par tsc
. En effet, il s’agit de JavaScript, non de TypeScript. Il en va de même avec TypeScript, si l’option strict
n’est pas activée : tsc
transpile l’instruction sans nous avertir.
normalizeName(undefined);
Cette instruction provoquera l’erreur TypeError: Cannot read property 'trim' of undefined
à l’exécution. Une erreur de runtime facilement évitable avec TypeScript et le mode strict
.
Changement de l’extension “js” en “ts”
En effet, avec l’option "strict"
à true
dans tsconfig.json
, on obtient l’erreur suivante en tentant de transpiler ce code TypeScript (normalize-name.ts
, notez l’extension .ts
) :
❌ normalize-name.ts(13,15): error TS2345: Argument of type ‘undefined’ is not assignable to parameter of type ‘string’
Pour un code TypeScript (.ts, .tsx), tsc
tient compte de la configuration établie dans tsconfig.json
.
Par conséquent, l’adoption progressive (fichier par fichier) peut se faire en deux temps. D’abord à l’aide de @ts-check
; ensuite en changeant l’extension js
du fichier en ts
.
💡 L’option
sourceMap
permet de générer les source maps correspondant au code transpilé.
Packages NPM et Imports
Pour les packages NPM importés dans le projet, tsc
s’attend à ce qu’ils possèdent un fichier de déclaration. Certains packages NPM en sont déjà équipés : c’est le cas idéal. Sinon il reste deux possibilités :
- Installer les packages DefinitelyTyped correspondants. Il en existe pour la plupart des packages (
@types/node
,@types/express
,@types/lodash
,@types/jest
, …). - Créer des déclarations vides (stubs) de ces packages, pour autoriser leur import sans qu’ils soient signalés comme inconnus (“Could not find a declaration file for module ’…’ […]”) :
declare module 'nom-du-module';
C’est une solution de “secours” lorsqu’aucun package @types
correspondant n’est disponible, ou qu’il n’est pas à jour. Vous pouvez aussi définir vous-même la déclaration du package et la partager avec la communauté.
Pour permettre l’import de fichiers JSON (import * as fileContent from './file.json'
) :
declare module '*.json' {
const value: any;
export default value;
}
💡 Pour générer les fichiers de déclaration de votre projet (par exemple, si c’est un projet open-source), activez l’option
declaration
.
Conclusion
Vous trouverez d’avantage de détails sur la migration depuis JavaScript dans la documentation officielle.
Une fois n’est pas coutume, j’insiste sur l’importance de l’option strict
. Comme le précise la documentation, elle entraîne l’activation de plusieurs règles (dont noImplicitAny
) qui rendent tsc
très exigeant sur la qualité (et le typage) de votre code mais permettent de tirer le meilleur profit de TypeScript.
Retrouvez-moi sur Twitter :
@VinceOPS