Préparation d'entretien 100% Gratuit angularforall.com

Entretien TypeScript Junior — Generics, Classes et Modules

Typescript Junior Quiz-Typescript-Junior Typescript-Generics Typescript-Classes Typescript-Modules Questions-Entretien-Typescript Qcm-Typescript-Junior Type-Narrowing Intersection-Types Decorateurs-Ts Front-End Back-End Ts-Avance
Junior 🔀 Mixte 20 questions ⏱ 15 min
📝

Entretien TypeScript Junior — Generics, Classes et Modules

20 questions TypeScript niveau junior : generics, classes, modules, types avancés (union, intersection), type narrowing et bonnes pratiques. Parfait pour réussir un entretien TypeScript Junior.

20 questions ⏱ ~15 min Niveau Junior

Partager

Banque de révision : les 30 questions corrigées

Voici l'intégralité des 30 questions de « Entretien TypeScript Junior — Generics, Classes et Modules », chacune avec sa bonne réponse et son explication. Le quiz interactif ci-dessus en tire une sélection aléatoire à chaque tentative — utilisez cette liste complète pour réviser.

  • Le typage statique qui permet de détecter les erreurs à la compilation plutôt qu'à l'exécution (bonne réponse)
  • TypeScript est plus rapide à l'exécution que JavaScript
  • TypeScript peut s'exécuter directement dans le navigateur sans compilation
  • TypeScript a moins de syntaxe que JavaScript
Explication : Le principal avantage de TypeScript est son système de typage statique. Il permet de détecter de nombreuses erreurs (mauvais type, propriété inexistante, etc.) pendant la compilation, avant que le code ne s'exécute dans le navigateur.
Cette détection précoce des erreurs est particulièrement précieuse dans les grandes applications ou quand on travaille en équipe.

  • Compile le fichier TypeScript en JavaScript (bonne réponse)
  • Exécute le fichier TypeScript directement
  • Vérifie la syntaxe sans compiler
  • Crée un fichier de configuration
Explication : La commande tsc (TypeScript Compiler) prend un fichier .ts et génère un fichier .js du même nom. Par exemple, tsc app.ts produit app.js.
Ajoutez l'option --watch (ou -w) pour que tsc recompile automatiquement à chaque modification.

  • let age: number = 25;
  • let age: int = 25;
  • let age = 25; (inférence automatique)
  • Les deux réponses A et C sont correctes (bonne réponse)
Explication : Les deux sont correctes. La syntaxe explicite let age: number = 25; et l'inférence automatique let age = 25; fonctionnent. TypeScript déduit que age est un nombre car 25 est un nombre.
L'inférence de type rend le code plus propre. Utilisez l'annotation explicite quand le type n'est pas évident ou quand vous voulez être explicite.

  • TypeScript génère une erreur à la compilation (bonne réponse)
  • Le code s'exécute normalement car JavaScript convertit automatiquement
  • TypeScript convertit silencieusement la valeur
  • Une erreur apparaît seulement à l'exécution
Explication : TypeScript vérifie les types à la compilation. Si vous essayez d'assigner une chaîne à une variable déclarée comme number, TypeScript lèvera une erreur : Type 'string' is not assignable to type 'number'.
C'est justement l'intérêt du typage statique : capturer ce genre d'erreur avant l'exécution.

  • let noms: string[] = ["Alice", "Bob"];
  • let noms: Array = ["Alice", "Bob"];
  • let noms = ["Alice", "Bob"]; (inférence automatique)
  • Toutes ces réponses sont correctes (bonne réponse)
Explication : Les trois syntaxes sont valides. string[] est la forme courte, Array<string> est la forme générique, et laisser TypeScript inférer depuis ["Alice", "Bob"] fonctionne aussi.
La syntaxe string[] est la plus courante et la plus lisible pour les débutants.

  • Il désactive la vérification de type ; à éviter sauf pour migrer du JS vers TS ou pour des cas très particuliers (bonne réponse)
  • C'est le type par défaut pour toutes les variables
  • Il permet de créer des variables qui peuvent changer de type
  • Il est recommandé pour toutes les variables
Explication : any est un type "fourre-tout" qui désactive la vérification de type. Il est utile lors de la migration progressive de JavaScript vers TypeScript, mais en général, il faut l'éviter car il annule les bénéfices de TypeScript.
Quand vous ne connaissez pas le type, préférez unknown à any : il est plus sécurisé car il force une vérification avant utilisation.

  • function add(a: number, b: number): number { return a + b; }
  • function add(a, b) { return a + b; }
  • const add = (a: number, b: number): number => a + b;
  • Toutes ces réponses sont correctes (bonne réponse)
Explication : Les trois syntaxes sont correctes. TypeScript peut inférer le type de retour même s'il n'est pas explicite. La première est une fonction classique typée, la seconde utilise l'inférence, la troisième est une fonction fléchée typée.
Pour les fonctions simples, les fonctions fléchées avec retour implicite sont très lisibles.

  • let a une portée de bloc, var a une portée de fonction (bonne réponse)
  • let ne peut pas être réassigné, var le peut
  • var est plus récent que let
  • Il n'y a pas de différence
Explication : let a une portée de bloc (délimitée par {}), tandis que var a une portée de fonction ou globale. let est généralement préféré car son comportement est plus prévisible.
En TypeScript moderne, utilisez toujours let ou const. Évitez var qui peut causer des bugs subtils.

  • La propriété est optionnelle (peut ne pas exister sur l'objet) (bonne réponse)
  • La propriété peut être null
  • La propriété est en lecture seule
  • La propriété est privée
Explication : Le ? rend une propriété optionnelle. Un objet conforme à l'interface peut avoir ou ne pas avoir cette propriété. Exemple : interface Personne { nom: string; age?: number; }
C'est très utile pour les paramètres de configuration ou les objets partiellement remplis.

  • interface Personne { nom: string; age: number; }
  • type Personne = { nom: string; age: number; }
  • class Personne { nom: string; age: number; }
  • Les deux réponses A et B sont correctes (bonne réponse)
Explication : Les deux syntaxes sont valides. interface est plus spécifique aux objets, type est plus général. Pour un simple objet, les deux fonctionnent, mais interface est souvent préférée car elle peut être étendue.
Utilisez interface par défaut pour décrire des objets. Utilisez type pour les unions, les tuples, ou les types primitifs.

  • Un type qui peut être de plusieurs types : let id: string | number; (bonne réponse)
  • Un type qui combine deux interfaces
  • Un type qui hérite d'un autre type
  • Un type réservé aux fonctions
Explication : Un type union permet à une variable d'accepter plusieurs types différents, séparés par le symbole | (pipe). Exemple : let id: string | number; accepte soit une chaîne, soit un nombre.
Pour utiliser une variable de type union, vous devrez souvent vérifier son type avec typeof avant d'utiliser des méthodes spécifiques.

  • function greet(name?: string): void { }
  • function greet(name: string | null): void { }
  • function greet(name = "Monde"): void { }
  • Les deux réponses A et C sont correctes (bonne réponse)
Explication : Les deux sont des façons valides de rendre un paramètre optionnel. Le ? le rend optionnel (peut être absent), la valeur par défaut le rend optionnel aussi (si non fourni, prend la valeur par défaut).
La valeur par défaut est souvent plus expressive car elle donne une valeur par défaut explicite.

  • La fonction ne retourne aucune valeur (bonne réponse)
  • La fonction retourne undefined
  • La fonction peut retourner n'importe quoi
  • La fonction est asynchrone
Explication : Le type void indique qu'une fonction ne retourne pas de valeur (ou retourne undefined implicitement). Exemple : function log(message: string): void { console.log(message); }
Une fonction void peut avoir un return; sans valeur, mais pas return valeur;.

  • function asyncFunc(): Promise { } (bonne réponse)
  • function asyncFunc(): Promise(number) { }
  • function asyncFunc(): number { }
  • function asyncFunc(): any { }
Explication : Une fonction asynchrone qui retourne une Promesse se type avec Promise<Type>. Ici, Promise<number> indique que la promesse se résout en un nombre.
Pour les fonctions async, le type de retour est automatiquement enveloppé dans une Promesse, mais il est recommandé de l'écrire explicitement.

  • Une assertion de type : dit au compilateur de considérer une valeur comme un certain type (bonne réponse)
  • Convertit la valeur à l'exécution
  • Crée une nouvelle instance
  • Vérifie si une valeur est d'un certain type
Explication : L'opérateur as est une assertion de type. Il indique au compilateur : "Je sais que cette valeur est de ce type, même si tu ne peux pas le prouver". Exemple : (event.target as HTMLInputElement).value.
L'assertion de type n'a pas d'effet à l'exécution. Si vous vous trompez de type, cela causera une erreur à l'exécution.

  • Un tableau avec un nombre fixe d'éléments et des types spécifiques à chaque position (bonne réponse)
  • Un tableau de taille variable
  • Un type spécial pour les objets
  • Une interface avec des méthodes
Explication : Un tuple est un tableau où la longueur est fixe et chaque position a un type prédéfini. Exemple : let personne: [string, number] = ["Alice", 30]; - la première position doit être une string, la seconde un nombre.
Les tuples sont parfaits pour représenter des paires ou des triplets de valeurs de types différents.

  • enum Jour { Lundi, Mardi, Mercredi, Jeudi, Vendredi }
  • type Jour = "Lundi" | "Mardi" | "Mercredi" | "Jeudi" | "Vendredi"
  • const Jour = { Lundi: 0, Mardi: 1, ... }
  • Les deux réponses A et B sont correctes mais ont des usages différents (bonne réponse)
Explication : Les deux approches sont valides. Les enums (enum) sont numériques par défaut. Les unions de strings littérales (type Jour = "Lundi" | ...) sont souvent préférées en TypeScript moderne car elles génèrent moins de code JavaScript.
Pour des valeurs simples, préférez les unions de strings littérales. Les enums sont utiles quand vous avez besoin d'une correspondance numérique.

  • Vous utilisez une variable ou fonction qui n'a pas été déclarée ou importée (bonne réponse)
  • Le fichier est corrompu
  • TypeScript ne peut pas compiler à cause d'une erreur de syntaxe
  • La variable existe mais a un type incorrect
Explication : Cette erreur apparaît quand vous référencez un identifiant (variable, fonction, classe) qui n'existe pas dans la portée courante. Soit vous avez oublié de le déclarer, soit vous n'avez pas fait l'import nécessaire.
Vérifiez que vous avez bien déclaré la variable avec let, const, ou var, ou que vous avez importé le module nécessaire.

  • class Personne { constructor(public nom: string, public age: number) { } }
  • class Personne { nom: string; age: number; constructor(nom: string, age: number) { this.nom = nom; this.age = age; } }
  • class Personne { constructor(nom, age) { this.nom = nom; this.age = age; } }
  • Les deux réponses A et B sont correctes (bonne réponse)
Explication : Les deux syntaxes sont valides. La syntaxe A utilise le raccourci TypeScript public nom: string dans le constructeur, qui déclare automatiquement la propriété et l'assigne. La syntaxe B est plus explicite et plus proche de JavaScript standard.
Le raccourci avec public (ou private, protected) dans le constructeur est très pratique et réduit le code boilerplate.

  • La propriété ne peut être modifiée qu'à l'initialisation ou dans le constructeur (bonne réponse)
  • La propriété est accessible partout mais ne peut pas être changée
  • La propriété est privée
  • La propriété est statique
Explication : readonly marque une propriété comme en lecture seule après son initialisation. Elle peut être assignée une fois (dans la déclaration ou dans le constructeur), mais pas modifiée ensuite.
Exemple : readonly id: number = 123; ou constructor(readonly id: number) { }

  • Une interface définit seulement la forme (le contrat) ; une classe contient l'implémentation (bonne réponse)
  • Une interface peut être instanciée, une classe non
  • Une classe ne peut pas implémenter d'interface
  • Il n'y a pas de différence
Explication : Une interface définit seulement la structure (propriétés et méthodes) sans implémentation. Une classe contient l'implémentation complète et peut être instanciée. Une classe peut implements une ou plusieurs interfaces.
Les interfaces n'existent qu'à la compilation. Elles n'apparaissent pas dans le JavaScript généré.

  • interface Chien extends Animal { aboyer(): void; }
  • interface Chien implements Animal { }
  • type Chien = Animal & { aboyer(): void; }
  • Les deux réponses A et C sont correctes (bonne réponse)
Explication : Les deux syntaxes permettent d'étendre. interface Chien extends Animal est la syntaxe classique d'héritage d'interface. type Chien = Animal & { ... } utilise l'intersection de types.
Pour les interfaces, préférez extends qui est plus lisible. Les intersections de types sont plus puissantes mais parfois moins claires.

  • type Comparateur = (a: number, b: number) => boolean; (bonne réponse)
  • type Comparateur = function(a: number, b: number): boolean;
  • type Comparateur = (number, number) => boolean;
  • type Comparateur = (a, b) => bool;
Explication : La syntaxe correcte pour un type de fonction est (paramètres) => type_retour. Exemple : type Comparateur = (a: number, b: number) => boolean;
Ces types de fonction sont très utiles pour typer des callbacks ou des paramètres de fonctions d'ordre supérieur.

  • TypeScript déduit automatiquement le type d'une variable basé sur sa valeur (bonne réponse)
  • Une erreur de compilation
  • Une fonction qui convertit les types
  • Un outil de débogage
Explication : L'inférence de type est la capacité de TypeScript à deviner le type d'une variable sans annotation explicite. Par exemple, let message = "Bonjour"; est automatiquement typé comme string.
L'inférence fonctionne bien pour les cas simples. Pour les fonctions complexes, les annotations explicites sont recommandées.

  • let nombres: readonly number[] = [1, 2, 3];
  • let nombres: ReadonlyArray = [1, 2, 3];
  • let nombres: const number[] = [1, 2, 3];
  • Les deux réponses A et B sont correctes (bonne réponse)
Explication : Les deux syntaxes créent un tableau en lecture seule. readonly number[] est la syntaxe courte, ReadonlyArray<number> est la syntaxe générique. Ces tableaux ne peuvent pas être modifiés (pas de push, pop, etc.).
Les tableaux en lecture seule sont une bonne pratique pour les données qui ne doivent pas être modifiées après création.

  • Empêche d'assigner null ou undefined à des variables sans l'avoir explicitement autorisé (bonne réponse)
  • Permet d'utiliser null partout
  • Désactive la vérification des null
  • Ajoute null à tous les types
Explication : Avec strictNullChecks: true, null et undefined ne sont pas automatiquement assignables aux autres types. Une variable de type string ne peut pas recevoir null ou undefined à moins d'utiliser un type union (string | null).
C'est l'une des options les plus importantes pour écrire du TypeScript robuste. Activez-la dans tous vos projets.

  • let nom: string | null = null; (bonne réponse)
  • let nom: string? = null;
  • let nom: optional string = null;
  • let nom: string = null; (si strictNullChecks est désactivé)
Explication : La syntaxe correcte est d'utiliser un type union : string | null. Cela indique que la variable peut contenir soit une chaîne, soit la valeur null.
Avec strictNullChecks: true, c'est obligatoire. Sans cette annotation, vous ne pourrez pas assigner null à une variable string.

  • (event: Event) => void
  • (event: any) => void
  • (event: MouseEvent) => void (pour un clic souris)
  • Toutes ces réponses peuvent être correctes selon le contexte (bonne réponse)
Explication : Le type le plus général est Event. Pour des événements spécifiques, utilisez le type approprié : MouseEvent (clic), KeyboardEvent (clavier), InputEvent (input), etc. any fonctionne mais perd l'intérêt du typage.
Exemple typique : onClick(event: MouseEvent) { console.log(event.clientX); }

  • Une fonction qui lance toujours une erreur ou ne se termine jamais (bonne réponse)
  • Une variable qui n'est jamais utilisée
  • Un synonyme de void
  • Un type pour les valeurs nulles
Explication : never représente une valeur qui ne se produit jamais. Exemple : function throwError(message: string): never { throw new Error(message); } La fonction ne retourne jamais car elle lance une exception.
never est aussi utile dans les unions exhaustives pour s'assurer que tous les cas sont traités.

  • Créer un fichier tsconfig.json à la racine et exécuter tsc sans paramètres
  • Utiliser tsc *.ts pour compiler tous les fichiers .ts
  • Utiliser tsc --project tsconfig.json
  • Toutes ces réponses sont correctes (bonne réponse)
Explication : La meilleure pratique est d'utiliser tsconfig.json. Une fois configuré, la commande tsc seule compile tous les fichiers spécifiés. On peut aussi utiliser tsc --project tsconfig.json ou tsc *.ts pour une compilation simple.
La configuration via tsconfig.json est recommandée pour les projets. Elle permet de définir les options de compilation une fois pour toutes.