Cours JavaScript et TypeScript · Module 6: Bases de TypeScript

Les type aliases

13 min de lecture
Dans cette leçon10

Bienvenue de nouveau au laboratoire de génétique de Jurassic Park ! Le Dr Henry Wu va aujourd'hui nous présenter un mécanisme extrêmement utile de TypeScript : les type aliases. Tout comme les scientifiques du parc utilisent des noms raccourcis pour désigner des séquences génétiques complexes, les développeurs utilisent les type aliases pour simplifier des définitions de types complexes.

Qu'est-ce qu'un type alias ?

Un type alias est simplement un nom que l'on donne à un type existant. On peut créer un alias aussi bien pour des types simples que pour des types complexes, ce qui rend le code plus lisible et plus facile à maintenir. C'est un peu comme donner un nom à différents mélanges d'ADN pour pouvoir s'y référer plus facilement pendant le travail en laboratoire.

Syntaxe de base

On définit un type alias à l'aide du mot-clé type :

1// Simple type alias for string
2type SpeciesID = string;
3
4// Using the alias
5const tRexID: SpeciesID = "TREX-01";
6const velociraptorID: SpeciesID = "VELOC-01";

Alias pour les types primitifs

On peut appliquer un type alias à des types simples, ce qui peut être utile pour la documentation et pour exprimer clairement l'intention du code :

1// Aliases for simple types
2type SecurityLevel = number;
3type SpeciesName = string;
4type IsPredator = boolean;
5
6// Function using type aliases
7function setEnclosureLevel(species: SpeciesName, predator: IsPredator): SecurityLevel {
8  if (predator) {
9    if (species === "Tyrannosaurus") return 5;
10    if (species === "Velociraptor") return 4;
11    return 3; // Other predators
12  } else {
13    return 2; // Herbivores
14  }
15}
16
17const trexLevel = setEnclosureLevel("Tyrannosaurus", true); // 5
18console.log(`Security level for T-Rex: ${trexLevel}`);

Alias pour les types complexes

Les type aliases deviennent particulièrement utiles pour définir des types complexes tels que des objets, des unions ou des tableaux :

1// Alias for object type (similar to interface)
2type Dinosaur = {
3  id: string;
4  name: string;
5  species: string;
6  age: number;
7  weight: number;
8  predator: boolean;
9};
10
11// Alias for union type - different identifiers
12type DinosaurID = string | number;
13
14// Alias for tuple - GPS coordinates with description
15type Location = [number, number, string];
16
17// Alias for array
18type SpeciesList = string[];
19
20// Alias for an object literal with optional fields
21type HealthStatus = {
22  overallHealth: "excellent" | "good" | "average" | "poor" | "critical";
23  temperature?: number;
24  heartRate?: number;
25  treatmentPriority?: 1 | 2 | 3 | 4 | 5;
26  notes?: string;
27};
28
29// Creating objects based on type aliases
30const rexLocation: Location = [35.6895, 139.6917, "T-Rex Enclosure, northern fence"];
31const parkSpecies: SpeciesList = ["Tyrannosaurus", "Velociraptor", "Triceratops", "Brachiosaurus"];
32
33const rexStatus: HealthStatus = {
34  overallHealth: "good",
35  temperature: 38.2,
36  treatmentPriority: 2,
37  notes: "Recently slightly reduced appetite"
38};
39
40// Function working on type alias
41function prepareDinosaurReport(dino: Dinosaur, status: HealthStatus, location: Location): string {
42  const [lat, lng, description] = location;
43
44  return `
45    Dinosaur report:
46    ID: ${dino.id}
47    Name: ${dino.name}
48    Species: ${dino.species}
49    Age: ${dino.age} years
50    Weight: ${dino.weight} kg
51    Predator: ${dino.predator ? "Yes" : "No"}
52
53    Health status: ${status.overallHealth}
54    ${status.temperature ? `Temperature: ${status.temperature}°C` : ""}
55    ${status.heartRate ? `Heart rate: ${status.heartRate} beats/min` : ""}
56
57    Location: ${description} (${lat}, ${lng})
58  `;
59}

Alias avec des types generic

Les type aliases peuvent aussi être generic, ce qui nous donne encore plus de flexibilité :

1// Generic type alias for monitoring system data
2type MonitoringData<T> = {
3  measurementTime: Date;
4  value: T;
5  unit: string;
6  valid: boolean;
7};
8
9// Using the generic type alias for different types of measurements
10type TemperatureMeasurement = MonitoringData<number>;
11type ActivityMeasurement = MonitoringData<"low" | "medium" | "high">;
12type StressLevelMeasurement = MonitoringData<1 | 2 | 3 | 4 | 5>;
13
14// Function analyzing monitoring data
15function analyzeData<T>(data: MonitoringData<T>): void {
16  console.log(`Measurement from ${data.measurementTime.toISOString()}`);
17  console.log(`Value: ${data.value} ${data.unit}`);
18  console.log(`Status: ${data.valid ? "Valid" : "Needs attention"}`);
19}
20
21// Sample usage
22const waterTemperature: TemperatureMeasurement = {
23  measurementTime: new Date(),
24  value: 24.5,
25  unit: "°C",
26  valid: true
27};
28
29const trexActivityLevel: ActivityMeasurement = {
30  measurementTime: new Date(),
31  value: "high",
32  unit: "activity level",
33  valid: false // Needs attention because T-Rex is too active
34};
35
36analyzeData(waterTemperature);
37analyzeData(trexActivityLevel);

Les type aliases récursifs

Un type alias peut être récursif, ce qui est utile pour modéliser des structures arborescentes comme les hiérarchies d'espèces de dinosaures ou l'organigramme du parc :

1// Recursive type alias for dinosaur category hierarchy
2type DinosaursCategory = {
3  name: string;
4  description?: string;
5  subcategories?: DinosaursCategory[];
6};
7
8// Creating a category hierarchy
9const taxonomy: DinosaursCategory = {
10  name: "Dinosaurs",
11  description: "Main classification of dinosaurs in Jurassic Park",
12  subcategories: [
13    {
14      name: "Theropods",
15      description: "Carnivorous, bipedal dinosaurs",
16      subcategories: [
17        {
18          name: "Tyrannosaurids",
19          subcategories: [
20            { name: "Tyrannosaurus Rex" }
21          ]
22        },
23        {
24          name: "Deinonychosaurs",
25          subcategories: [
26            { name: "Velociraptor" },
27            { name: "Deinonychus" }
28          ]
29        }
30      ]
31    },
32    {
33      name: "Sauropods",
34      description: "Large, four-legged herbivores with long necks",
35      subcategories: [
36        { name: "Brachiosaurus" },
37        { name: "Diplodocus" }
38      ]
39    }
40  ]
41};
42
43// Function to render the taxonomy tree
44function displayTaxonomy(category: DinosaursCategory, level: number = 0): void {
45  const indent = "  ".repeat(level);
46  console.log(`${indent}${category.name}`);
47
48  if (category.description) {
49    console.log(`${indent}  Description: ${category.description}`);
50  }
51
52  if (category.subcategories && category.subcategories.length > 0) {
53    category.subcategories.forEach(subcategory => {
54      displayTaxonomy(subcategory, level + 1);
55    });
56  }
57}
58
59displayTaxonomy(taxonomy);

Type aliases vs interfaces

On compare souvent les type aliases aux interfaces, car dans de nombreux cas ils peuvent être utilisés de manière interchangeable. Il existe cependant quelques différences clés entre eux :

1// Structure definition using interface
2interface DinosaurInterface {
3  id: string;
4  name: string;
5  species: string;
6}
7
8// Equivalent definition using type alias
9type DinosaurType = {
10  id: string;
11  name: string;
12  species: string;
13};
14
15// Both work similarly for basic use
16const dino1: DinosaurInterface = { id: "001", name: "Rex", species: "Tyrannosaurus" };
17const dino2: DinosaurType = { id: "002", name: "Blue", species: "Velociraptor" };

Différences clés entre les type aliases et les interfaces

  1. Extensibilité :

    • Les interfaces peuvent être étendues en les déclarant plusieurs fois
    • Les type aliases ne peuvent pas être « rouverts » : une fois défini, un alias ne peut plus être étendu par la suite
    1// Interface can be extended by multiple declarations
    2interface AnimalInterface {
    3  id: string;
    4  species: string;
    5}
    6
    7// Adding new fields to the existing interface
    8interface AnimalInterface {
    9  age: number;
    10  weight: number;
    11}
    12
    13// Now AnimalInterface has all four fields
    14const animal: AnimalInterface = {
    15  id: "001",
    16  species: "Tyrannosaurus",
    17  age: 7,
    18  weight: 7000
    19};
    20
    21// A type alias cannot be extended this way
    22type AnimalType = {
    23  id: string;
    24  species: string;
    25}
    26
    27// This would cause an error: Duplicate identifier 'AnimalType'
    28// type AnimalType = {
    29//   age: number;
    30//   weight: number;
    31// }
  2. Types complexes :

    • Les type aliases peuvent représenter directement des unions, des intersections et d'autres types avancés
    • Les interfaces sont davantage centrées sur la définition de la forme des objets
    1// Only possible with type aliases
    2type SecurityStatus = "normal" | "elevated" | "threat";
    3type GPSCoordinates = [number, number];
    4type AnimalID = string | number;
    5
    6// With interfaces this would be more cumbersome
  3. Les interfaces pour les classes :

    • Les interfaces sont le choix naturel pour définir les contrats que les classes doivent implémenter
    • Les type aliases sont plus flexibles pour définir des types complexes
    1// Interface for a class
    2interface MonitoringSystem {
    3  start(): void;
    4  stop(): void;
    5  getStatus(): string;
    6}
    7
    8// Class implementing the interface
    9class EnclosureMonitoring implements MonitoringSystem {
    10  start() { console.log("Enclosure monitoring started"); }
    11  stop() { console.log("Enclosure monitoring stopped"); }
    12  getStatus() { return "Active"; }
    13}

Combiner les type aliases avec d'autres fonctionnalités de TypeScript

Les type aliases peuvent être combinés avec d'autres fonctionnalités de TypeScript, ce qui permet de créer des abstractions puissantes :

1// Combining with union types
2type DinosaurData =
3  | { type: "basic"; id: string; species: string }
4  | { type: "extended"; id: string; species: string; age: number; weight: number }
5  | { type: "full"; id: string; species: string; age: number; weight: number; history: string[]; healthStatus: string };
6
7// Function processing different levels of data
8function processDinosaurData(data: DinosaurData): void {
9  console.log(`Processing data for ID: ${data.id}, species: ${data.species}`);
10
11  // We use the discriminated union to determine the data type
12  switch (data.type) {
13    case "basic":
14      console.log("Processing basic data");
15      break;
16    case "extended":
17      console.log(`Age: ${data.age}, Weight: ${data.weight} kg`);
18      break;
19    case "full":
20      console.log(`Age: ${data.age}, Weight: ${data.weight} kg`);
21      console.log(`History: ${data.history.join(", ")}`);
22      console.log(`Health status: ${data.healthStatus}`);
23      break;
24  }
25}
26
27// Usage examples
28const basic: DinosaurData = {
29  type: "basic",
30  id: "TRX-001",
31  species: "Tyrannosaurus"
32};
33
34const extended: DinosaurData = {
35  type: "extended",
36  id: "VEL-001",
37  species: "Velociraptor",
38  age: 4,
39  weight: 150
40};
41
42const full: DinosaurData = {
43  type: "full",
44  id: "TRI-001",
45  species: "Triceratops",
46  age: 10,
47  weight: 8000,
48  history: ["Born: 2013", "Transfer from Location B: 2016", "Broken horns: 2018", "Recovery: 2019"],
49  healthStatus: "Good"
50};
51
52processDinosaurData(basic);
53processDinosaurData(extended);
54processDinosaurData(full);

Combiner les types utilitaires avec les type aliases

TypeScript propose des types utilitaires intégrés que l'on peut combiner avec les type aliases, ce qui nous donne encore plus de possibilités pour modéliser nos données :

1// Base interface for a dinosaur
2interface Dinosaur {
3  id: string;
4  name: string;
5  species: string;
6  age: number;
7  weight: number;
8  gender: "male" | "female";
9  predator: boolean;
10  nocturnal: boolean;
11  healthStatus: "excellent" | "good" | "needs attention" | "sick" | "critical";
12}
13
14// Type aliases using utility types
15
16// Read-only type - useful for data that should not be modified
17type DinosaurReadOnly = Readonly<Dinosaur>;
18
19// Type with selected fields - useful for partial data
20type DinosaurBasic = Pick<Dinosaur, "id" | "name" | "species">;
21
22// Type with omitted fields - useful when we want to exclude certain data
23type DinosaurWithoutStatus = Omit<Dinosaur, "healthStatus">;
24
25// Type with optional fields - useful for partial updates
26type DinosaurPartial = Partial<Dinosaur>;
27
28// Type with required fields - forcing all fields to be defined
29type DinosaurRequired = Required<Dinosaur>;
30
31// Record type - useful for key-indexed collections
32type DinosaursDatabase = Record<string, Dinosaur>;
33
34// Usage examples
35const rexReadOnly: DinosaurReadOnly = {
36  id: "TRX-001",
37  name: "Rex",
38  species: "Tyrannosaurus",
39  age: 7,
40  weight: 7000,
41  gender: "female",
42  predator: true,
43  nocturnal: false,
44  healthStatus: "good"
45};
46
47// rexReadOnly.age = 8; // Error: Cannot assign to 'age' because it is a read-only property
48
49const rexBasic: DinosaurBasic = {
50  id: "TRX-001",
51  name: "Rex",
52  species: "Tyrannosaurus"
53};
54
55// Partial data update
56function updateDinosaurData(id: string, data: DinosaurPartial): void {
57  console.log(`Updating data for dinosaur ${id}`);
58  console.log(data);
59  // In a real application we would update the data in the database
60}
61
62updateDinosaurData("TRX-001", {
63  age: 8,
64  weight: 7200,
65  healthStatus: "needs attention"
66});
67
68// Dinosaur database
69const database: DinosaursDatabase = {
70  "TRX-001": {
71    id: "TRX-001",
72    name: "Rex",
73    species: "Tyrannosaurus",
74    age: 7,
75    weight: 7000,
76    gender: "female",
77    predator: true,
78    nocturnal: false,
79    healthStatus: "good"
80  },
81  "VEL-001": {
82    id: "VEL-001",
83    name: "Blue",
84    species: "Velociraptor",
85    age: 4,
86    weight: 150,
87    gender: "female",
88    predator: true,
89    nocturnal: true,
90    healthStatus: "excellent"
91  }
92};
93
94console.log(`Number of dinosaurs in the database: ${Object.keys(database).length}`);

Exemple pratique : le modèle de données de Jurassic Park

Voyons maintenant comment utiliser les type aliases avec d'autres fonctionnalités de TypeScript pour créer un modèle de données complet pour le système de gestion de Jurassic Park :

1// Base types
2type ID = string;
3type Coordinates = [number, number];
4type AccessLevel = 1 | 2 | 3 | 4 | 5;
5type ActivityStatus = "active" | "inactive" | "under maintenance";
6type HealthStatus = "excellent" | "good" | "needs attention" | "sick" | "critical";
7
8// Dinosaur types
9type TaxonomicGroup = "theropods" | "sauropods" | "ceratopsians" | "stegosaurs" | "ankylosaurs";
10
11type DietClass = "herbivore" | "carnivore" | "omnivore";
12
13type SpeciesData = {
14  name: string;
15  taxonomicGroup: TaxonomicGroup;
16  diet: DietClass;
17  geologicalEra: string;
18  averageWeight: number;
19  averageLength: number;
20  averageAge: number;
21  threat: AccessLevel;
22  description: string;
23};
24
25type Specimen = {
26  id: ID;
27  species: string;
28  firstName: string;
29  age: number;
30  weight: number;
31  gender: "male" | "female";
32  status: HealthStatus;
33  location: ID;
34  arrivalDate: Date;
35  history: MedicalHistory[];
36};
37
38type MedicalHistory = {
39  date: Date;
40  type: "examination" | "treatment" | "vaccination" | "surgery";
41  description: string;
42  veterinarian: ID;
43};
44
45// Employee types
46type Position =
47  | "director"
48  | "researcher"
49  | "veterinarian"
50  | "trainer"
51  | "security"
52  | "maintenance"
53  | "technician"
54  | "guide";
55
56type Employee = {
57  id: ID;
58  firstName: string;
59  lastName: string;
60  position: Position;
61  accessLevel: AccessLevel;
62  hireDate: Date;
63  contact: {
64    phone: string;
65    email: string;
66    address?: string;
67  };
68  specializationAreas?: string[];
69};
70
71// Location types
72type LocationType =
73  | "enclosure"
74  | "laboratory"
75  | "operations center"
76  | "public zone"
77  | "dining"
78  | "shop"
79  | "attraction";
80
81type SecuritySystems = {
82  fence: boolean;
83  videoMonitoring: boolean;
84  motionSensors: boolean;
85  backupPower: boolean;
86  electricVoltage?: number; // only for predator enclosures
87};
88
89type Location = {
90  id: ID;
91  name: string;
92  type: LocationType;
93  coordinates: Coordinates;
94  area: number; // in hectares
95  capacity: number; // maximum number of people/specimens
96  requiredAccessLevel: AccessLevel;
97  status: ActivityStatus;
98  securitySystems: SecuritySystems;
99};
100
101// Event types
102type EventType =
103  | "dinosaurEscape"
104  | "systemFailure"
105  | "accident"
106  | "illness"
107  | "birth"
108  | "death"
109  | "specimenTransfer"
110  | "weatherThreat";
111
112type Event = {
113  id: ID;
114  type: EventType;
115  date: Date;
116  location: ID;
117  dinosaurParticipants?: ID[];
118  employeeParticipants?: ID[];
119  description: string;
120  status: "in progress" | "resolved" | "closed";
121  priority: 1 | 2 | 3 | 4 | 5;
122  preventiveActions?: string[];
123};
124
125// Park management system
126type ManagementSystem = {
127  dinosaurs: Record<ID, Specimen>;
128  species: Record<string, SpeciesData>;
129  employees: Record<ID, Employee>;
130  locations: Record<ID, Location>;
131  events: Record<ID, Event>;
132
133  // System methods
134  addSpecimen: (specimen: Omit<Specimen, "id">) => ID;
135  updateSpecimenStatus: (id: ID, status: HealthStatus) => void;
136  moveSpecimen: (id: ID, newLocation: ID) => boolean;
137  findSpecimens: (filters: Partial<Specimen>) => Specimen[];
138  generateStatusReport: () => StatusReport;
139};
140
141type StatusReport = {
142  specimenCount: number;
143  speciesDistribution: Record<string, number>;
144  healthStatuses: Record<HealthStatus, number>;
145  locationOccupancy: Record<ID, { capacity: number; current: number }>;
146  recentEvents: Event[];
147  alerts: string[];
148};
149
150// Simulating part of the system
151const jurassicParkSystem: Partial<ManagementSystem> = {
152  dinosaurs: {},
153  species: {
154    "Tyrannosaurus": {
155      name: "Tyrannosaurus Rex",
156      taxonomicGroup: "theropods",
157      diet: "carnivore",
158      geologicalEra: "late Cretaceous",
159      averageWeight: 7000,
160      averageLength: 12,
161      averageAge: 30,
162      threat: 5,
163      description: "One of the largest predators that ever walked the Earth."
164    },
165    "Velociraptor": {
166      name: "Velociraptor",
167      taxonomicGroup: "theropods",
168      diet: "carnivore",
169      geologicalEra: "late Cretaceous",
170      averageWeight: 15,
171      averageLength: 1.8,
172      averageAge: 25,
173      threat: 4,
174      description: "Small, fast and intelligent predator, hunting in packs."
175    }
176  },
177  locations: {
178    "LOC-001": {
179      id: "LOC-001",
180      name: "T-Rex Paddock",
181      type: "enclosure",
182      coordinates: [20.1234, -75.8765],
183      area: 8,
184      capacity: 2,
185      requiredAccessLevel: 4,
186      status: "active",
187      securitySystems: {
188        fence: true,
189        videoMonitoring: true,
190        motionSensors: true,
191        backupPower: true,
192        electricVoltage: 10000
193      }
194    }
195  }
196};
197
198// Function demonstrating usage of the types
199function demonstrateManagementSystem() {
200  console.log("Jurassic Park Management System");
201  console.log("----------------------------------");
202
203  console.log("Available species:");
204  Object.values(jurassicParkSystem.species || {}).forEach(species => {
205    console.log(`- ${species.name} (${species.diet}, threat: ${species.threat})`);
206  });
207
208  console.log("\nAvailable locations:");
209  Object.values(jurassicParkSystem.locations || {}).forEach(loc => {
210    console.log(`- ${loc.name} (type: ${loc.type}, status: ${loc.status}, access: level ${loc.requiredAccessLevel})`);
211  });
212}
213
214demonstrateManagementSystem();

Résumé

Les type aliases en TypeScript sont un mécanisme puissant qui permet d'écrire un code plus lisible, plus facile à maintenir et plus sûr. Dans le contexte de la gestion d'un système aussi complexe que Jurassic Park, les type aliases nous permettent de modéliser précisément les données et les relations qui existent entre elles.

Fonctionnalité du type aliasUtilisation à Jurassic Park
Alias de baseTypes d'identifiants, niveaux de sécurité
Type aliases complexesStructures de données pour les dinosaures, les employés, les emplacements
Alias genericSystème de surveillance pour différents paramètres
Types récursifsHiérarchies d'espèces, organigramme
Unions discriminéesDifférents niveaux de données, types d'événements
Types utilitairesGestion de la mutabilité et de l'accessibilité des données

Le Dr Wu résume ainsi : « Les type aliases sont comme nos check-lists et nos protocoles de laboratoire : ils nous permettent de définir clairement à quoi doivent ressembler les données et les opérations, tout en rendant l'ensemble du système plus compréhensible. Dans un projet aussi complexe que Jurassic Park, où la moindre erreur peut avoir des conséquences catastrophiques, des outils aussi précis n'ont pas de prix. »

Code de cette leçon : index.ts
1// Type Aliases dans le Parc Jurassique
2console.log("Type Aliases TypeScript\n");
3
4// ===========================================
5// 1. Type aliases de base
6// ===========================================
7console.log("=== TYPE ALIASES DE BASE ===");
8
9// Alias for simple types
10type DinosaurID = string | number;
11type Weight = number;
12type Species = string;
13
14let id1: DinosaurID = "DINO-001";
15let id2: DinosaurID = 123;
16let weight: Weight = 8000;
17let species: Species = "Tyrannosaurus Rex";
18
19console.log("ID:", id1, id2);
20console.log("Weight:", weight);
21console.log("Species:", species);
22
23// ===========================================
24// 2. Type vs Interface
25// ===========================================
26console.log("\n=== TYPE VS INTERFACE ===");
27
28// Type alias
29type DinosaurType = {
30  name: string;
31  species: string;
32  age: number;
33};
34
35// Interface
36interface DinosaurInterface {
37  name: string;
38  species: string;
39  age: number;
40}
41
42const dino1: DinosaurType = {
43  name: "Rex",
44  species: "T-Rex",
45  age: 5
46};
47
48const dino2: DinosaurInterface = {
49  name: "Blue",
50  species: "Velociraptor",
51  age: 3
52};
53
54console.log("Type:", dino1);
55console.log("Interface:", dino2);
56
57// ===========================================
58// 3. Union types avec des aliases
59// ===========================================
60console.log("\n=== UNION TYPES ===");
61
62type Diet = "carnivore" | "herbivore" | "omnivore";
63type Period = "Triassic" | "Jurassic" | "Cretaceous";
64type SecurityLevel = "low" | "medium" | "high" | "critical";
65
66type Dinosaur = {
67  name: string;
68  diet: Diet;
69  period: Period;
70  dangerLevel: SecurityLevel;
71};
72
73const trex: Dinosaur = {
74  name: "Tyrannosaurus Rex",
75  diet: "carnivore",
76  period: "Cretaceous",
77  dangerLevel: "critical"
78};
79
80console.log("T-Rex:", trex);
81
82// ===========================================
83// 4. Intersection types avec des aliases
84// ===========================================
85console.log("\n=== INTERSECTION TYPES ===");
86
87type HasName = {
88  name: string;
89};
90
91type HasWeight = {
92  weight: number;
93};
94
95type HasDiet = {
96  diet: Diet;
97};
98
99// Combining types
100type CompleteDinosaur = HasName & HasWeight & HasDiet & {
101  species: string;
102};
103
104const velociraptor: CompleteDinosaur = {
105  name: "Blue",
106  weight: 350,
107  diet: "carnivore",
108  species: "Velociraptor"
109};
110
111console.log("Complete dinosaur:", velociraptor);
112
113// ===========================================
114// 5. Function types
115// ===========================================
116console.log("\n=== FUNCTION TYPES ===");
117
118// Type function
119type DinosaurFilter = (dino: Dinosaur) => boolean;
120type DinosaurTransformer = (dino: Dinosaur) => string;
121type DinosaurComparator = (a: Dinosaur, b: Dinosaur) => number;
122
123const carnivoreFilter: DinosaurFilter = (dino) => dino.diet === "carnivore";
124const nameTransformer: DinosaurTransformer = (dino) => `${dino.name}`;
125const dangerComparator: DinosaurComparator = (a, b) => {
126  const levels = { low: 1, medium: 2, high: 3, critical: 4 };
127  return levels[b.dangerLevel] - levels[a.dangerLevel];
128};
129
130console.log("Is carnivore:", carnivoreFilter(trex));
131console.log("Transformed:", nameTransformer(trex));
132
133// ===========================================
134// 6. Tuple types
135// ===========================================
136console.log("\n=== TUPLE TYPES ===");
137
138type Coordinates = [latitude: number, longitude: number];
139type DinosaurData = [name: string, weight: number, isCarnivore: boolean];
140type RGB = [red: number, green: number, blue: number];
141
142const paddockLocation: Coordinates = [22.3964, -159.5261];
143const dinoInfo: DinosaurData = ["Rexy", 8000, true];
144const warningColor: RGB = [255, 0, 0];
145
146console.log("Location:", paddockLocation);
147console.log("Dino info:", dinoInfo);
148console.log("Warning color:", warningColor);
149
150// ===========================================
151// 7. Mapped types avec des aliases
152// ===========================================
153console.log("\n=== MAPPED TYPES ===");
154
155type DinosaurStats = {
156  health: number;
157  hunger: number;
158  energy: number;
159  happiness: number;
160};
161
162// All fields comme readonly
163type ReadonlyStats = {
164  readonly [K in keyof DinosaurStats]: DinosaurStats[K];
165};
166
167// All fields comme optionnels
168type PartialStats = {
169  [K in keyof DinosaurStats]?: DinosaurStats[K];
170};
171
172const stats: DinosaurStats = {
173  health: 100,
174  hunger: 50,
175  energy: 80,
176  happiness: 90
177};
178
179const readonlyStats: ReadonlyStats = stats;
180// readonlyStats.health = 90; // Error
181
182const partialStats: PartialStats = {
183  health: 100,
184  energy: 80
185  // remaining fields optional
186};
187
188console.log("Stats:", stats);
189console.log("Partial stats:", partialStats);
190
191// ===========================================
192// 8. Conditional types
193// ===========================================
194console.log("\n=== CONDITIONAL TYPES ===");
195
196// Conditional type
197type IsCarnivore<T> = T extends { diet: "carnivore" } ? true : false;
198
199type TRexIsCarnivore = IsCarnivore<typeof trex>; // true
200type VelociraptorIsCarnivore = IsCarnivore<typeof velociraptor>; // true
201
202// Extract - extracts types satisfying condition
203type DinosaurSize = "small" | "medium" | "large" | "extra-large";
204type LargeSizes = Extract<DinosaurSize, "large" | "extra-large">;
205
206// Exclude - removes types satisfying condition
207type SmallMediumSizes = Exclude<DinosaurSize, "large" | "extra-large">;
208
209console.log("Conditional types defined");
210
211// ===========================================
212// 9. Utility types z aliases
213// ===========================================
214console.log("\n=== UTILITY TYPES ===");
215
216type BaseDinosaur = {
217  id: string;
218  name: string;
219  species: string;
220  weight: number;
221};
222
223// Partial - tous les fields optionnels
224type PartialDinosaur = Partial<BaseDinosaur>;
225
226// Required - tous les fields obligatoires
227type RequiredDinosaur = Required<BaseDinosaur>;
228
229// Pick - select specific fields
230type DinosaurSummary = Pick<BaseDinosaur, "name" | "species">;
231
232// Omit - remove specific fields
233type PublicDinosaur = Omit<BaseDinosaur, "id">;
234
235// Record - mapping des clés vers un type
236type DinosaurCollection = Record<string, BaseDinosaur>;
237
238const partialDino: PartialDinosaur = {
239  name: "Rex"
240  // tous les autres fields optionnels
241};
242
243const summary: DinosaurSummary = {
244  name: "Rexy",
245  species: "T-Rex"
246};
247
248const collection: DinosaurCollection = {
249  "t-rex": {
250    id: "001",
251    name: "Rexy",
252    species: "T-Rex",
253    weight: 8000
254  },
255  "velociraptor": {
256    id: "002",
257    name: "Blue",
258    species: "Velociraptor",
259    weight: 350
260  }
261};
262
263console.log("Partial:", partialDino);
264console.log("Summary:", summary);
265console.log("Collection:", collection);
266
267// ===========================================
268// 10. Résumé
269// ===========================================
270console.log("\n=== RÉSUMÉ ===");
271console.log("Type Aliases - names for types");
272console.log("Union & Intersection - combining types");
273console.log("Function Types - types de function");
274console.log("Tuple Types - tuples");
275console.log("Mapped Types - type transformation");
276console.log("Conditional Types - types conditionnels");
277console.log("Utility Types - built-in tools");
278
279console.log("\nType Aliases maîtrisés !");

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Qu’est-ce qu’un alias de type en TypeScript ?

  2. 2. Qu’est-ce qu’une garde de type (type guard) en TypeScript ?

Voici 2 des 3 questions de cette leçon. Réponds aux autres dans le jeu.

Tâches pratiques dans le jeu

  • Éditeur de code

    Crée un alias de type DinoStatus et une fonction avec une garde de type qui vérifie si un dinosaure est carnivore.

  • Clique dans l'ordre

    Ordonne les éléments d’une assertion de type en TypeScript :

  • Tri vertical

    Ordonne les méthodes de vérification de type en TypeScript de la plus simple à la plus avancée :

Articles utiles