Introduction : pourquoi les interfaces ne fonctionnent-elles pas à l'exécution ?
\n\nSalut, l'ami ! Si tu as déjà écrit du TypeScript, tu as sûrement rencontré cette situation : tu crées une interface parfaite, tu décris tous les champs, tu vérifies les types à la compilation — et soudain tu réalises qu'à l'exécution (runtime), ton code se comporte comme si les interfaces n'existaient pas. Ça te dit quelque chose ? 🎯
\n\nC'est l'une des questions les plus populaires sur Stack Overflow : "Interface type check with TypeScript" — des milliers de vues, des centaines de réponses. Et ce n'est pas surprenant, car TypeScript efface les interfaces lors de la compilation. Contrairement aux classes, les interfaces sont une construction purement déclarative pour le développeur et le compilateur. En JavaScript, elles n'existent pas.
\n\nDans cet article, nous allons voir comment contourner cette limitation, apprendre à vérifier la conformité d'un objet à une interface à l'exécution et répondre aux questions les plus fréquentes. C'est parti ! 🚀
\n\nPourquoi voulons-nous vérifier les interfaces ?
\n\nImagine : tu reçois des données d'une API, d'un formulaire ou d'un WebSocket. Tu es sûr qu'elles correspondent à l'interface User, mais soudain un objet arrive sans le champ email ou avec un type incorrect. Si tu ne vérifies pas — ton code plantera avec une erreur. Les interfaces TypeScript ne vérifient qu'au moment du développement, pas en production. Il faut donc des vérifications à l'exécution.
Le problème : les interfaces n'existent pas à l'exécution
\n\nEn TypeScript, les interfaces sont du "sucre syntaxique" pour le typage statique. Lorsque tu compiles le code, les interfaces disparaissent. Voici un exemple simple :
\n\ninterface User {\n name: string;\n age: number;\n}\n\nconst data: unknown = JSON.parse('{"name": "Alice"}');\nif (data instanceof User) { // ❌ Erreur ! User est une interface, pas une classe\n console.log(data.name);\n}\n\nLe compilateur dira : 'User' only refers to a type, but is being used as a value here. C'est le piège principal pour les débutants. Mais ne t'inquiète pas — il existe plusieurs méthodes éprouvées pour contourner cela.
Méthode 1 : Gardiens de types personnalisés (User-Defined Type Guards)
\n\nLa méthode la plus populaire et élégante est d'écrire une fonction de gardien de type. Elle vérifie la structure de l'objet et retourne true/false, et TypeScript "comprend" qu'à l'intérieur du bloc avec true, l'objet correspond bien à l'interface.
interface User {\n name: string;\n age: number;\n email?: string; // champ optionnel\n}\n\nfunction isUser(obj: unknown): obj is User {\n if (typeof obj !== 'object' || obj === null) return false;\n\n const user = obj as Record<string, unknown>;\n return (\n typeof user.name === 'string' &&\n typeof user.age === 'number' &&\n (user.email === undefined || typeof user.email === 'string')\n );\n}\n\n// Exemple d'utilisation\nconst data: unknown = JSON.parse('{"name": "Bob", "age": 30}');\n\nif (isUser(data)) {\n // Maintenant TypeScript sait que data est un User\n console.log(data.name.toUpperCase()); // ✅ Fonctionne\n}\n\nAvantages : contrôle total, les types sont correctement déduits, facile à étendre.
\nInconvénients : il faut écrire manuellement pour chaque interface (mais il existe des bibliothèques !)
Qu'est-ce que obj is User ?
\n\nC'est la syntaxe du gardien de type. Elle dit à TypeScript : "Si la fonction retourne true, alors l'argument obj peut être considéré comme étant de type User". C'est la magie qui rend la vérification à l'exécution utile pour l'analyse statique.
Méthode 2 : Utiliser des classes au lieu d'interfaces
\n\nLes classes sont la seule construction TypeScript qui est conservée en JavaScript. Si tu as besoin de vérifier le type à l'exécution, tu peux remplacer l'interface par une classe avec une vérification via instanceof.
class User {\n constructor(\n public name: string,\n public age: number,\n public email?: string\n ) {}\n}\n\nconst data = new User('Charlie', 25);\nif (data instanceof User) {\n consol