Interfaces et alias de types génériques
Définissez des interfaces et des alias de types génériques, ajoutez des contraintes et des valeurs par défaut, et comprenez les atouts de chacun.
Interfaces et alias de types génériques est une leçon TypeScript Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 3. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage TypeScript Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours TypeScript Academy comprend 3 leçons au total.
Introduction
Objectif : créer des structures réutilisables avec des interfaces génériques et des alias de type. Vous ajouterez des contraintes et des valeurs par défaut, et apprendrez les principales différences.
Vue d’ensemble de la leçon
Objectif : appliquer la concurrence structurée avec coroutineScope, comprendre la propagation des exceptions et utiliser les outils d’annulation en toute sécurité.
Idées clés
- coroutineScope attend tous les enfants ; un échec annule les frères.
- launch échoue immédiatement dans la portée ; async expose les erreurs lors de l’appel de await().
- withTimeout annule le travail après une limite.
- Entourez les portées d’un bloc try/catch pour gérer les exceptions.
Interface générique
Une interface générique contient un paramètre de type. Les appelants lui substituent des types concrets (par exemple, Box<number>).
interface Box<T> {
value: T;
}
const nBox: Box<number> = { value: 42 };
const sBox: Box<string> = { value: "ts" };
console.log(nBox.value, sBox.value);Alias de type générique
Un alias de type peut également être générique et représenter des objets, des fonctions, des unions ou des intersections.
type Pair<A, B> = { first: A; second: B };
const p1: Pair<number, string> = { first: 1, second: "one" };
const p2: Pair<boolean, boolean> = { first: true, second: false };
console.log(p1, p2);Comportement d’attente de la portée
coroutineScope crée une portée enfant qui ne se termine qu’après l’achèvement de ses enfants.
import kotlinx.coroutines.*
suspend fun doTwoTasks(): Unit = coroutineScope {
// Both run concurrently and the scope waits for them
launch { delay(150); println("Task A done") }
launch { delay(100); println("Task B done") }
// returning Unit implicitly after children complete
}
fun main() = runBlocking {
doTwoTasks()
println("Scope completed")
}Un échec annule les frères
Si un enfant déclenche une exception, la portée annule les frères et relance l’exception vers l’appelant ; utilisez try/catch sur le site d’appel.
import kotlinx.coroutines.*
suspend fun failingGroup() = coroutineScope {
val a = launch {
try {
repeat(5) { i ->
println("A $i"); delay(60)
}
} finally {
println("A cancelled")
}
}
launch {
delay(120)
throw IllegalStateException("boom") // failure in child
}
a.join() // will be cancelled when sibling fails
}
fun main() = runBlocking {
try {
failingGroup()
} catch (e: Exception) {
println("Caught in caller: ${e.message}")
}
println("Caller continues")
}Contraintes
Ajoutez une contrainte extends afin que T expose les membres requis aux méthodes de l'interface (par exemple, id).
interface Repository<T extends { id: number }> {
getById(id: number): T | undefined;
save(entity: T): void;
}
type User = { id: number; name: string };
const memRepo: Repository<User> = {
store: [] as User[],
getById(id) {
return this.store.find(u => u.id === id);
},
save(u) {
this.store.push(u);
}
} as unknown as Repository<User>;
memRepo.save({ id: 1, name: "Ada" });
console.log(memRepo.getById(1));Erreurs de async + await
Les exceptions de async sont déclenchées lorsque vous appelez await() ; gérez-les avec try/catch.
import kotlinx.coroutines.*
suspend fun parseAsync(s: String) = coroutineScope {
val deferred = async {
delay(50)
s.toInt() // may throw NumberFormatException
}
try {
println("Result = ${deferred.await()}") // error appears here
} catch (e: NumberFormatException) {
println("Handled parse error: ${e::class.simpleName}")
}
}
fun main() = runBlocking {
parseAsync("12")
parseAsync("xx")
}Paramètres par défaut et extension
Fournissez des paramètres de type par défaut pour faciliter l'utilisation et construisez sur les types avec des utilitaires (par exemple, Readonly<Box<T>>).
interface ApiResponse<T = unknown> {
data: T;
ok: boolean;
}
type ReadonlyBox<T> = Readonly<Box<T>>;
const r1: ApiResponse = { data: "ok", ok: true }; // T defaults to unknown
const r2: ApiResponse<number> = { data: 200, ok: true };
const rb: ReadonlyBox<string> = { value: "fixed" };
// rb.value = "change"; // Error: readonlyAnnulation avec withTimeout
Utilisez withTimeout pour limiter la durée du travail ; cette fonction annule l’enfant et déclenche TimeoutCancellationException.
import kotlinx.coroutines.*
suspend fun slowOp(): Int {
delay(300) // pretend work
return 42
}
fun main() = runBlocking {
try {
val result = withTimeout(150) { slowOp() } // cancels after 150ms
println("Got $result")
} catch (e: TimeoutCancellationException) {
println("Timed out and cancelled")
}
}Différences de fusion
Les interfaces prennent en charge la fusion des déclarations. Les alias de type ne peuvent pas être fusionnés ; les noms en double sont des erreurs.
interface Settings { theme: string }
interface Settings { lang: string }
// Merged: Settings has { theme: string; lang: string }
const s: Settings = { theme: "dark", lang: "en" };
// type Settings = { foo: string };
// Error: Duplicate identifier 'Settings' for type aliases (no merging)Règle d’échec de la concurrence structurée
Vérification : interfaces ou alias de type
Vérification rapide : quelle affirmation concernant les interfaces génériques et les alias de type est TRUE ?
Récapitulatif
Récapitulatif : utilisez les interfaces génériques et les alias de type pour modéliser des structures réutilisables. Ajoutez des contraintes et des valeurs par défaut, et retenez ceci : seules les interfaces fusionnent.
Récapitulatif
Récapitulatif : utilisez coroutineScope pour regrouper le travail ; un enfant défaillant annule les frères. Gérez les erreurs avec try/catch, exposez les échecs de async avec await() et annulez les tâches longues avec withTimeout.
Questions Fréquemment Posées
La leçon « Interfaces et alias de types génériques » est-elle gratuite ?
Oui — le texte complet de « Interfaces et alias de types génériques » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours TypeScript Academy, passe à CoddyKit PRO. Le cours TypeScript Academy comprend 3 leçons au total.
Qu'est-ce que j'apprendrai dans « Interfaces et alias de types génériques » ?
Définissez des interfaces et des alias de types génériques, ajoutez des contraintes et des valeurs par défaut, et comprenez les atouts de chacun. Tu pratiques TypeScript Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer TypeScript Academy ?
Aucune expérience préalable n'est requise. TypeScript Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 3.
Combien de temps prend la leçon « Interfaces et alias de types génériques » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon TypeScript Academy ?
Oui. Chaque leçon TypeScript Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Interfaces et alias de types génériques
- Types conditionnels (introduction) et distribution sur les unions
- Motifs réutilisables pour les modèles de données