Quel usage de Typescript à ITN ?
Pourquoi utiliser typescript ?
Typescript apporte plusieurs avantages par rapport à du JavaScript classique:
- Eviter les typo sur les noms de variables et les fonctions
- Faciliter l'autocompletion
- Faciliter la compréhension du code pour les nouveaux arrivants
- Eviter les erreurs d'envoi d'arguments de fonctions
Quelle différence avec le typage PHP ?
Contrairement à PHP, Typescript défini la "forme" des variables attendues et non pas leur type. Cela signifie que c'est avant tout une surcouche à JavaScript qui permet de définir des interfaces et des types pour les variables et les fonctions, mais qui ne va pas vérifier le type des variables à l'exécution.
Concrètement cela signifie que typescript ne fournit aucune manière de faire des conditions sur le type des variables (contrairement à PHP avec instanceof, get_classname, etc...). Il est important de garder en tête cette différence : typescript n'a aucune influence sur le code JavaScript généré, il ne sert qu'à faciliter l'écriture et la lecture de code JavaScript.
Comment configurer typescript ?
Etant donné que nous utilisons uniquement Next.js et Storybook pour les nouveaux projets, il n'est pas nécessaire de gérer de la configuration spécifique, il suffit de créer les fichiers en .tsx au lieu de .jsx.
Un point important à noter est que Next.js ne vérifie pas les erreurs typescript en mode dev (pour des raisons de performance), il est donc recommandé de lancer un tsc --watch en parallèle pour vérifier les erreurs de typage si vous ne faites pas confiance à votre IDE.
Comment utiliser typescript ?
Un point important à se rappeler lorsque l'on utilise typescript est qu'il faut parfois savoir s'arrêter lorsque l'on part trop loin dans le typage fort.
Une fois que l'on maitrise les concepts de base, il est important de ne pas perdre de vue l'objectif principal de typescript qui est de faciliter la compréhension du code et d'éviter les erreurs de typo.
Interface et type
Il est possible de définir des interfaces et des types en typescript. Il est recommandé de privilégier des interfaces plutot que des types.
Une interface s'écrit de cette manière
interface User {
name: string;
age: number;
}
Cela permet de définir un objet qui doit avoir un nom et un age.
Voila comment on peut utiliser cette interface
function printUser(user: User) {
console.log(`Name: ${user.name}, Age: ${user.age}`);
}
const user = { name: 'John', age: 30 };
printUser(user);
Vous trouverez tous les types basiques ici: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html La plupart du temps c'est du string, du number et du boolean.
Il est également possible de référence une autre interface dans une interface
interface Group {
name: string;
users: User[];
}
Cette interface définit un groupe qui a un nom et une liste d'utilisateurs.
Pour écrire les interfaces à partir de JSON à la vitesse de l'éclair, pensez à utiliser votre ami github copilot chat.
Pour les allergiques aux chats, vous avez aussi https://quicktype.io/
Les types génériques
Les types génériques sont des sortes de factory de type.
Prenons l'exemple d'un résultat de recherche: on connait la forme de l'objet de recherche, mais suivant l'appel d'api que l'on fait, nous n'aurons pas forcément les mêmes données.
interface SearchResult<Entity> {
results: Entity[];
resultNumber: number;
}
Beaucoup d'exemples d'usage de génériques utilisent le mot T pour désigner le type générique, mais il est fortement encouragé d'utiliser un nom plus explicite pour faciliter la compréhension du code (on ne nomme pas ses variables a, b, c normalement...).
la partie entre les chevrons <> est le type générique, il permet de définir un type qui sera utilisé dans l'interface.
Si on réutilise l'exemple de l'utilisateur, on peut définir une interface de résultat de recherche pour les utilisateurs de cette manière:
function searchUsers(query: string): SearchResult<User> {
return {
results: [
{ name: 'John', age: 30 },
{ name: 'Jane', age: 25 },
],
resultNumber: 2,
};
}
L'appelant de cette fonction est donc assuré que le résultat de la recherche contiendra des utilisateurs dans le tableau results.
Ou mettre les définitions ?
Si l'interface est utilisée dans un seul fichier, il est recommandé de la déclarer directement dans le fichier (props de composant par exemple).
function Hello({firstName}: { firstName: string }) {
return <div>hello {firstName}</div>
}
Si l'interface a vocation à étre utilisée dans plusieurs fichiers, il est recommandé de la déclarer dans un dossier types dans le dossier front du projet.
Pour les gros projets ayant des séparations par module il est recomandé de faire un fichier types.ts par dossier
Je ne suis pas certain de la bonne manière de gérer un type spécifique
Avant de demander à quelqu'un d'autre, je vous conseille de poser la question à monsieur github copilot chat, il est souvent étonnamment juste dans ses propositions.
Sinon, vous pouvez aussi demander à quelqu'un d'autre si le chat n'est pas en forme aujourd'hui :p
Comment bien utiliser Typescript avec PHPstorm ?
Autocompletion
Etant donné que PHPstorm est capable de suivre les types des variables (si le projet est typé correctement), il est possible d'avoir une autocompletion de qualité sur les variables.
Pensez à utiliser le raccourcis ctrl + espace pour afficher l'autocompletion.

Vérification de type
Il est possible d'afficher le type d'une variable en passant la souris dessus. C'est très pratique pour vérifier que le type d'une variable est bien celui attendu.
Il est ensuite possible de cliquer sur le type pour afficher le détail de son implémentation

Cette fonctionalité est très pratique pour comprendre le code et vérifier que les types sont bien définis, et notamment éviter les problémes de "leaking any".
Refactoring
Etant donné que PHPstorm est capable de comprendre tous les endroits où un type est utilisé, vous pouvez renommer un type en toute sécurité avec la fonctionnalité de refactoring de PHPstorm.

Typescript et React
Je conseille de lire la Documentation React officielle pour l'usage avec typescript qui est trés bien écrite.
Typescript et les librairies externes
De plus en plus de librairies sont typées en typescript. Pensez à utiliser les types indiqués dans la documentation pour facilter le typage de vos fonctions utilisant la librairie.
Par exemple lorsque l'on veut donner un lien Next.js à un composant, on peut utiliser le type LinkProps fourni par Next.js pour s'assurer que l'on passe bien les bonnes props.
import NextLink from 'next/link';
import {LinkProps} from "next/dist/client/link";
function MyComponent({link} : {link: LinkProps}) {
return (
<div>
<h1>My Component</h1>
<NextLink {...link}>
<a >
Let's go HERE !
</a>
</NextLink>
</div>
);
}