Nous sommes parfois amenés à traiter des objets similaires en Typescript et il faut de temps en temps les différencier pour adapter leur traitement.
Imaginons que nous ayons des entités Employee qui héritent une partie de leurs propriétés d’une entité de base Person.
Voyons comment, à l’aide d’exemples simples, nous pouvons différencier leur traitement en faisant du type checking.
(NB: les noms des entités précisent volontairement les types d’entités par soucis de clarté)
Avec des classes
Nous sommes en effet ici dans un cas typique où la POO peut nous apporter pas mal d’avantages.
Supposons que nous ayons besoin d’une fonction qui nous fournisse une chaîne de caractères représentant les informations des Person/Employee traités. Nous pourrions utiliser le mot clé instanceof
pour déterminer de quelle instance de classe est l’objet traité.
Ok, Ok! Je vois d’ici les puristes s’exclamer, et à raison.
Nous sommes ici dans l’illustration.
Tant qu’à faire de la POO, nous devrions plutôt déclarer notre fonction toString()
dans la classe!
L’inconvénient des classes dans une utilisation classique dans un frontend est qu’il faudra à chaque réponse d’une requête HTTP ou à chaque création d’un objet, créer les instances de classe avec le constructeur. (new EmployeeClass(firstName, ...)
)
Avec des types / interfaces
Reprenons l’exemple précédent mais en utilisant des objets et des types. Nous pourrions écrire:
Se pose alors le problème suivant:
Comment discerner les objets selon leur type pour éviter l’erreur ci-dessous?
Nous pourrions commencer par écrire la fonction toString()
comme ceci.
Attention, le mot clé in
sert à déterminer si la propriété existe dans l’objet, pas la valeur!
Le test sur la présence de la propriété est suffisant dans ce cas, mais pas totalement discriminant.
Certains pourraient être tentés d’utiliser l’opérateur typeof
pour savoir de quel type est l’objet. Mais cela ne fonctionne qu’avec les types primitifs!
Nous pouvons, par contre, créer une fonction qui va nous permettre de determiner si l’objet est exactement du type PersonType et une autre pour savoir si l’objet est exactement du type EmployeeType. Vous noterez l’utilisation du type unknown
qui signifie que le paramètre aura un type déterminé qu’on ne connait pas pour le moment, à l’inverse de any
qui veut plutôt dire que le paramètre sera de n’importe quel type.
Même si ce code est tout à fait valable, Typescript nous donne 3 erreurs:
En effet, nous avons réussi à determiner si toutes les caractéristiques de nos entités passées en paramètres de nos fonctions répondaient à celles attendues par nos types, mais nous n’avons pas indiqué à Typescript que nos entités sont bien de ces types.
Pour cela, nous avons l’opérateur is
qui va se positionner sur le type de retour des fonctions précédentes.
L’opérateur is
est utile ici uniquement pour une vérification statique (static type checking = avant de transpiler le code, dans l’IDE). En effet, le code Javascript généré n’en tient pas compte:
Par honnêteté intellectuelle, je me dois de vous dire que ces fonctions ne sont pas sûres à 100% non plus. On pourrait augmenter leur niveau de sureté en vérifiant le type de chacun des attributs! 😅
Chaque développeur doit estimer où placer le curseur de la sureté en fonction du besoin!