We use cookies to enhance your experience on the site
CodeWorlds

Extending interfaces

Welcome back to Jurassic Park! Today Dr. Henry Wu will guide us through an advanced TypeScript technique that is the foundation of building scalable and flexible systems - extending interfaces. Just as scientists in the park extend the basic traits of dinosaurs with new genetic properties, in TypeScript we can extend basic interfaces with new functionality.

Basic mechanism of extending interfaces

Extending interfaces in TypeScript allows us to create new interfaces on the basis of existing ones, adding new properties or methods. We use the

extends
keyword:

1// Base interface for all creatures in the park
2interface Creature {
3  id: string;
4  name: string;
5  species: string;
6  age: number;
7  weight: number;
8}
9
10// Extending the base interface with additional properties for dinosaurs
11interface Dinosaur extends Creature {
12  originEra: string; // e.g. "Jurassic", "Cretaceous"
13  diet: "herbivore" | "carnivore" | "omnivore";
14  dangerous: boolean;
15}
16
17// Now the Dinosaur interface contains all fields from Creature plus its own
18const trex: Dinosaur = {
19  id: "TREX-01",
20  name: "Rex",
21  species: "Tyrannosaurus Rex",
22  age: 7,
23  weight: 7000,
24  originEra: "Cretaceous",
25  diet: "carnivore",
26  dangerous: true
27};

Extending multiple interfaces

An interface can extend multiple other interfaces simultaneously, allowing complex types to be composed from smaller, specialized parts - similar to how scientists combine DNA from different species to create hybrids:

1// Interface defining predator abilities
2interface PredatorAbilities {
3  biteForce: number; // in PSI
4  runSpeed: number; // in km/h
5  huntingStyle: "ambush" | "chase" | "pack";
6}
7
8// Interface defining aquatic animal traits
9interface AquaticAnimal {
10  swimmingAbility: number; // 1 to 10
11  maxDepth: number; // in meters
12  saltWaterResistance: boolean;
13}
14
15// Interface for a marine predator combining both of the above interfaces
16interface MarinePredator extends PredatorAbilities, AquaticAnimal {
17  scientificName: string;
18}
19
20// Creating a dinosaur that is a marine predator
21const mosasaurus: MarinePredator & Dinosaur = {
22  // Properties from Creature
23  id: "MOSA-01",
24  name: "Mosa",
25  species: "Mosasaurus",
26  age: 15,
27  weight: 15000,
28
29  // Properties from Dinosaur
30  originEra: "Cretaceous",
31  diet: "carnivore",
32  dangerous: true,
33
34  // Properties from PredatorAbilities
35  biteForce: 18000,
36  runSpeed: 0, // doesn't run, swims
37  huntingStyle: "ambush",
38
39  // Properties from AquaticAnimal
40  swimmingAbility: 9,
41  maxDepth: 500,
42  saltWaterResistance: true,
43
44  // Properties from MarinePredator
45  scientificName: "Mosasaurus hoffmannii"
46};
47
48// Demonstration of accessing different properties
49function analyzeMarinePredator(dino: MarinePredator & Dinosaur): void {
50  console.log(`Analyzing: ${dino.name} (${dino.species})`);
51  console.log(`Bite force: ${dino.biteForce} PSI`);
52  console.log(`Can dive to depth: ${dino.maxDepth} meters`);
53  console.log(`Visitor threat: ${dino.dangerous ? "HIGH" : "LOW"}`);
54}
55
56analyzeMarinePredator(mosasaurus);

Extending interfaces vs class inheritance

Extending interfaces is similar to class inheritance, but has several key differences. In Jurassic Park, this can be compared to the difference between "description of an ideal dinosaur" (interface) and "an actual dinosaur" (class):

1// Interface for security systems
2interface SecuritySystem {
3  name: string;
4  securityLevel: number;
5  isActive: boolean;
6
7  activate(): void;
8  deactivate(): void;
9  test(): boolean;
10}
11
12// Class implementing the interface
13class ElectronicFence implements SecuritySystem {
14  name: string;
15  securityLevel: number;
16  isActive: boolean;
17  voltage: number; // additional property specific to this class
18
19  constructor(name: string, securityLevel: number, voltage: number) {
20    this.name = name;
21    this.securityLevel = securityLevel;
22    this.isActive = false;
23    this.voltage = voltage;
24  }
25
26  activate(): void {
27    this.isActive = true;
28    console.log(`System ${this.name} activated with voltage ${this.voltage}V`);
29  }
30
31  deactivate(): void {
32    this.isActive = false;
33    console.log(`System ${this.name} deactivated`);
34  }
35
36  test(): boolean {
37    console.log(`Testing system ${this.name}...`);
38    return Math.random() > 0.1; // 90% chance of successful test
39  }
40
41  // Method specific to this class
42  increaseVoltage(by: number): void {
43    this.voltage += by;
44    console.log(`Voltage increased to ${this.voltage}V`);
45  }
46}
47
48// Extended version of SecuritySystem for more advanced systems
49interface AdvancedSecuritySystem extends SecuritySystem {
50  backupPower: boolean;
51  videoMonitoring: boolean;
52  alarmNotifications: boolean;
53
54  runSecurityProcedure(threatLevel: number): void;
55}
56
57// Class implementing the extended interface
58class IntegratedSecuritySystem implements AdvancedSecuritySystem {
59  name: string;
60  securityLevel: number;
61  isActive: boolean;
62  backupPower: boolean;
63  videoMonitoring: boolean;
64  alarmNotifications: boolean;
65
66  constructor(name: string, securityLevel: number) {
67    this.name = name;
68    this.securityLevel = securityLevel;
69    this.isActive = false;
70    this.backupPower = true;
71    this.videoMonitoring = true;
72    this.alarmNotifications = true;
73  }
74
75  activate(): void {
76    this.isActive = true;
77    console.log(`Integrated system ${this.name} activated`);
78  }
79
80  deactivate(): void {
81    this.isActive = false;
82    console.log(`Integrated system ${this.name} deactivated`);
83  }
84
85  test(): boolean {
86    console.log(`Testing integrated system ${this.name}...`);
87    const powerTest = Math.random() > 0.05;
88    const monitoringTest = Math.random() > 0.05;
89    const notificationsTest = Math.random() > 0.05;
90
91    return powerTest && monitoringTest && notificationsTest;
92  }
93
94  runSecurityProcedure(threatLevel: number): void {
95    console.log(`Activating security procedure level ${threatLevel} for system ${this.name}`);
96    this.activate();
97
98    if (threatLevel >= 4) {
99      console.log("WARNING: High threat level! Activating all security measures!");
100    }
101  }
102}
103
104// Usage demonstration
105const trexFence = new ElectronicFence("T-Rex Enclosure", 5, 10000);
106trexFence.activate();
107trexFence.increaseVoltage(2000);
108
109const integratedParkSystem = new IntegratedSecuritySystem("Main System", 5);
110integratedParkSystem.runSecurityProcedure(4);

Extending and implementing generic interfaces

Generic interfaces are especially powerful when modeling complex systems, such as monitoring different types of data in the park:

1// Generic interface for a monitoring system
2interface MonitoringSystemType<T> {
3  identyfikator: string;
4  typDanych: string;
5  aktualneDane: T;
6  historyczneDane: T[];
7
8  zapisz(dane: T): void;
9  pobierzOstatnie(n: number): T[];
10  analizujTrend(): string;
11}
12
13// Sample data type for environmental monitoring
14interface EnvironmentalData {
15  temperatura: number;
16  humidity: number;
17  poziomCO2: number;
18  sunExposure: number;
19  pressure: number;
20  czasPomiaru: Date;
21}
22
23// Implementation of monitoring system for a specific data type
24class EnvironmentalMonitoring implements MonitoringSystemType<EnvironmentalData> {
25  identyfikator: string;
26  typDanych: string;
27  aktualneDane: EnvironmentalData;
28  historyczneDane: EnvironmentalData[];
29
30  constructor(identyfikator: string) {
31    this.identyfikator = identyfikator;
32    this.typDanych = "environmental";
33    this.aktualneDane = {
34      temperatura: 0,
35      humidity: 0,
36      poziomCO2: 0,
37      sunExposure: 0,
38      pressure: 0,
39      czasPomiaru: new Date()
40    };
41    this.historyczneDane = [];
42  }
43
44  zapisz(dane: EnvironmentalData): void {
45    this.aktualneDane = dane;
46    this.historyczneDane.push(dane);
47    console.log(`Saved new data for monitor ${this.identyfikator} at ${dane.czasPomiaru.toISOString()}`);
48  }
49
50  pobierzOstatnie(n: number): EnvironmentalData[] {
51    return this.historyczneDane.slice(-n);
52  }
53
54  analizujTrend(): string {
55    if (this.historyczneDane.length < 2) {
56      return "Not enough data to analyze trend";
57    }
58
59    const ostatnie = this.historyczneDane[this.historyczneDane.length - 1];
60    const przedostatnie = this.historyczneDane[this.historyczneDane.length - 2];
61
62    let trendy = [];
63
64    if (ostatnie.temperatura > przedostatnie.temperatura) {
65      trendy.push("Temperature: RISING");
66    } else if (ostatnie.temperatura < przedostatnie.temperatura) {
67      trendy.push("Temperature: FALLING");
68    } else {
69      trendy.push("Temperature: STABLE");
70    }
71
72    if (ostatnie.humidity > przedostatnie.humidity) {
73      trendy.push("Humidity: RISING");
74    } else if (ostatnie.humidity < przedostatnie.humidity) {
75      trendy.push("Humidity: FALLING");
76    } else {
77      trendy.push("Humidity: STABLE");
78    }
79
80    return trendy.join(", ");
81  }
82
83  // Method specific to environmental monitoring
84  temperatureWarning(): boolean {
85    return this.aktualneDane.temperatura > 35 || this.aktualneDane.temperatura < 15;
86  }
87}
88
89// Extending the base interface with specific functions for dinosaur monitoring
90interface DinosaurMonitoringSystem<T> extends MonitoringSystemType<T> {
91  idDinosaura: string;
92  species: string;
93  progiAlarmowe: Partial<T>;
94
95  checkAlarmThresholds(): boolean;
96  sendAlertIfNeeded(): void;
97}
98
99// Data type for dinosaur health monitoring
100interface DinosaurHealthData {
101  bodyTemperature: number;
102  heartRate: number;
103  bloodPressure: [number, number]; // [systolic, diastolic]
104  poziomStresu: number; // 1-10
105  activityLevel: number; // 1-10
106  czasPomiaru: Date;
107}
108
109// Implementation of specific monitoring system for dinosaurs
110class DinosaurHealthMonitoring implements DinosaurMonitoringSystem<DinosaurHealthData> {
111  identyfikator: string;
112  typDanych: string;
113  aktualneDane: DinosaurHealthData;
114  historyczneDane: DinosaurHealthData[];
115  idDinosaura: string;
116  species: string;
117  progiAlarmowe: Partial<DinosaurHealthData>;
118
119  constructor(identyfikator: string, idDinosaura: string, species: string) {
120    this.identyfikator = identyfikator;
121    this.typDanych = "health";
122    this.aktualneDane = {
123      bodyTemperature: 0,
124      heartRate: 0,
125      bloodPressure: [0, 0],
126      poziomStresu: 0,
127      activityLevel: 0,
128      czasPomiaru: new Date()
129    };
130    this.historyczneDane = [];
131    this.idDinosaura = idDinosaura;
132    this.species = species;
133
134    // Setting alarm thresholds based on species
135    if (species === "Tyrannosaurus") {
136      this.progiAlarmowe = {
137        bodyTemperature: 39, // Above this temperature - alarm
138        heartRate: 95, // Above this heart rate - alarm
139        poziomStresu: 7 // Above this stress level - alarm
140      };
141    } else if (species === "Velociraptor") {
142      this.progiAlarmowe = {
143        bodyTemperature: 40,
144        heartRate: 120,
145        poziomStresu: 8
146      };
147    } else {
148      // Default thresholds for other species
149      this.progiAlarmowe = {
150        bodyTemperature: 38,
151        heartRate: 100,
152        poziomStresu: 7
153      };
154    }
155  }
156
157  zapisz(dane: DinosaurHealthData): void {
158    this.aktualneDane = dane;
159    this.historyczneDane.push(dane);
160    console.log(`Saved new health data for dinosaur ${this.idDinosaura} (${this.species})`);
161
162    // Check if values exceed thresholds
163    this.sendAlertIfNeeded();
164  }
165
166  pobierzOstatnie(n: number): DinosaurHealthData[] {
167    return this.historyczneDane.slice(-n);
168  }
169
170  analizujTrend(): string {
171    if (this.historyczneDane.length < 2) {
172      return "Not enough data to analyze trend";
173    }
174
175    return "Health trend analysis (sample implementation)";
176  }
177
178  checkAlarmThresholds(): boolean {
179    let thresholdExceeded = false;
180
181    if (this.progiAlarmowe.bodyTemperature &&
182        this.aktualneDane.bodyTemperature > this.progiAlarmowe.bodyTemperature) {
183      console.log(`ALARM: Dinosaur ${this.idDinosaura} body temperature exceeds threshold!`);
184      thresholdExceeded = true;
185    }
186
187    if (this.progiAlarmowe.heartRate &&
188        this.aktualneDane.heartRate > this.progiAlarmowe.heartRate) {
189      console.log(`ALARM: Dinosaur ${this.idDinosaura} heart rate exceeds threshold!`);
190      thresholdExceeded = true;
191    }
192
193    if (this.progiAlarmowe.poziomStresu &&
194        this.aktualneDane.poziomStresu > this.progiAlarmowe.poziomStresu) {
195      console.log(`ALARM: Dinosaur ${this.idDinosaura} stress level exceeds threshold!`);
196      thresholdExceeded = true;
197    }
198
199    return thresholdExceeded;
200  }
201
202  sendAlertIfNeeded(): void {
203    if (this.checkAlarmThresholds()) {
204      console.log(`Sending alert to veterinary team for dinosaur ${this.idDinosaura}!`);
205    }
206  }
207
208  // Method specific to dinosaur health monitoring
209  recommendIntervention(): string {
210    let rekomendacje = [];
211
212    if (this.aktualneDane.bodyTemperature > this.progiAlarmowe.bodyTemperature!) {
213      rekomendacje.push("Lower body temperature");
214    }
215
216    if (this.aktualneDane.poziomStresu > this.progiAlarmowe.poziomStresu!) {
217      rekomendacje.push("Administer sedatives");
218    }
219
220    if (this.aktualneDane.activityLevel < 3) {
221      rekomendacje.push("Check energy level and possibly increase food portion");
222    }
223
224    return rekomendacje.length > 0
225      ? `Recommended actions: ${rekomendacje.join(", ")}`
226      : "No recommendations - parameters within normal range";
227  }
228}
229
230// Example usage
231const monitorPaddockTRex = new EnvironmentalMonitoring("ENV-TREX-01");
232monitorPaddockTRex.zapisz({
233  temperatura: 28.5,
234  humidity: 75,
235  poziomCO2: 420,
236  sunExposure: 80,
237  pressure: 1013,
238  czasPomiaru: new Date()
239});
240
241const monitorRexy = new DinosaurHealthMonitoring("HEALTH-TREX-01", "TREX-01", "Tyrannosaurus");
242monitorRexy.zapisz({
243  bodyTemperature: 38.2,
244  heartRate: 72,
245  bloodPressure: [135, 85],
246  poziomStresu: 3,
247  activityLevel: 4,
248  czasPomiaru: new Date()
249});
250
251// Simulating a health problem
252monitorRexy.zapisz({
253  bodyTemperature: 40.1, // Fever!
254  heartRate: 98, // Elevated heart rate
255  bloodPressure: [155, 95], // High blood pressure
256  poziomStresu: 8, // High stress level
257  activityLevel: 2, // Low activity
258  czasPomiaru: new Date()
259});
260
261console.log(monitorRexy.recommendIntervention());

Interface declaration merging

One of the unique features of TypeScript is the ability to merge multiple declarations of the same interface - similar to how Jurassic Park scientists can update their handling protocols as they gain new information:

1// Initial definition of the security protocol
2interface SecurityProtocolType {
3  id: string;
4  nazwa: string;
5  threatLevel: 1 | 2 | 3 | 4 | 5;
6  proceduraEwakuacji: string;
7}
8
9// Later extension of the same interface with additional information
10interface SecurityProtocolType {
11  personelOdpowiedzialny: string[];
12  czasReakcji: number; // in minutes
13}
14
15// Even later extension with communication procedures
16interface SecurityProtocolType {
17  communicationChannels: string[];
18  alarmMessage: string;
19}
20
21// Now SecurityProtocolType has all fields from all three declarations
22const protocolAlpha: SecurityProtocolType = {
23  id: "PROTO-ALFA",
24  nazwa: "Protocol Alpha - Predator Escape",
25  threatLevel: 5,
26  proceduraEwakuacji: "Immediate evacuation of all public areas to safety bunkers",
27  personelOdpowiedzialny: ["Security manager", "Park manager", "Head trainer"],
28  czasReakcji: 5,
29  communicationChannels: ["Radio", "PA System", "Audible alarm", "SMS notifications"],
30  alarmMessage: "ATTENTION! PROTOCOL ALPHA! This is not a drill. Please immediately proceed to the nearest shelter."
31};
32
33// Function to display the protocol
34function displayProtocol(protocol: SecurityProtocolType): void {
35  console.log(`=== ${protocol.nazwa.toUpperCase()} ===`);
36  console.log(`ID: ${protocol.id}`);
37  console.log(`Threat level: ${protocol.threatLevel}`);
38  console.log(`Response time: ${protocol.czasReakcji} minutes`);
39  console.log(`\nEvacuation procedure:\n${protocol.proceduraEwakuacji}`);
40  console.log(`\nResponsible personnel:`);
41  protocol.personelOdpowiedzialny.forEach(osoba => console.log(`- ${osoba}`));
42  console.log(`\nCommunication channels: ${protocol.communicationChannels.join(", ")}`);
43  console.log(`\nAlarm message: "${protocol.alarmMessage}"`);
44}
45
46displayProtocol(protocolAlpha);

Structural compatibility of interfaces

TypeScript uses structural compatibility, meaning types are compatible if they have the same structure, regardless of their names. It's like in Jurassic Park - if a dinosaur behaves like a T-Rex and looks like a T-Rex, from the security system's perspective it should be treated like a T-Rex:

1// Definition of a predatory dinosaur interface
2interface PredatoryDinosaur {
3  id: string;
4  nazwa: string;
5  biteForce: number;
6  runSpeed: number;
7  poziomAgresji: number;
8}
9
10// Completely separate definition, with no formal relationship to the above interface
11interface DangerousCreature {
12  id: string;
13  nazwa: string;
14  biteForce: number;
15  runSpeed: number;
16  poziomAgresji: number;
17  // Additional field that does not interfere with compatibility
18  pochodzenie?: string;
19}
20
21function assessThreat(dino: PredatoryDinosaur): number {
22  return (dino.biteForce / 1000) + (dino.runSpeed / 10) + dino.poziomAgresji;
23}
24
25// Creating an object conforming to DangerousCreature
26const indominus: DangerousCreature = {
27  id: "IND-01",
28  nazwa: "Indominus Rex",
29  biteForce: 15000,
30  runSpeed: 48,
31  poziomAgresji: 10,
32  pochodzenie: "Laboratory"
33};
34
35// Even though indominus is of type DangerousCreature, it can be used where
36// PredatoryDinosaur is expected, thanks to structural compatibility
37const threatLevel = assessThreat(indominus);
38console.log(`Threat level for ${indominus.nazwa}: ${threatLevel}`);
39
40// Function expecting an object conforming to DangerousCreature
41function describeThreat(creature: DangerousCreature): string {
42  let opis = `${creature.nazwa} is an extremely dangerous creature.\n`;
43  opis += `Bite force: ${creature.biteForce} PSI\n`;
44  opis += `Running speed: ${creature.runSpeed} km/h\n`;
45  opis += `Aggression level: ${creature.poziomAgresji}/10\n`;
46
47  if (creature.pochodzenie) {
48    opis += `Created in: ${creature.pochodzenie}`;
49  }
50
51  return opis;
52}
53
54// Creating an object conforming to PredatoryDinosaur
55const velociraptor: PredatoryDinosaur = {
56  id: "VEL-01",
57  nazwa: "Blue",
58  biteForce: 4000,
59  runSpeed: 65,
60  poziomAgresji: 7
61};
62
63// We can use an object of type PredatoryDinosaur in a function expecting DangerousCreature
64// It works because velociraptor has all the required properties
65const opisRaptora = describeThreat(velociraptor);
66console.log(opisRaptora);

Interfaces vs abstract types

Comparing interfaces with abstract types (abstract classes) in the context of Jurassic Park:

1// Interface for security systems
2interface SecuritySystemInterface {
3  nazwa: string;
4  aktywuj(): void;
5  dezaktywuj(): void;
6  testuj(): boolean;
7}
8
9// Abstract class for security systems
10abstract class SecuritySystemAbstractClass {
11  constructor(public nazwa: string, protected securityLevel: number) {}
12
13  abstract aktywuj(): void;
14  abstract dezaktywuj(): void;
15
16  // Shared implementation for all derived classes
17  testuj(): boolean {
18    console.log(`Testing system ${this.nazwa}...`);
19    return Math.random() > 0.1; // 90% chance of success
20  }
21
22  // Method available to all derived classes
23  pobierzPoziom(): number {
24    return this.securityLevel;
25  }
26}
27
28// Interface implementation
29class SkaneryRuchu implements SecuritySystemInterface {
30  constructor(public nazwa: string) {}
31
32  aktywuj(): void {
33    console.log(`Motion scanners ${this.nazwa} activated`);
34  }
35
36  dezaktywuj(): void {
37    console.log(`Motion scanners ${this.nazwa} deactivated`);
38  }
39
40  testuj(): boolean {
41    console.log(`Testing motion scanners ${this.nazwa}...`);
42    return true;
43  }
44}
45
46// Extending the abstract class
47class ElektroniczneOgrodzenie extends SecuritySystemAbstractClass {
48  private voltage: number;
49
50  constructor(nazwa: string, securityLevel: number, voltage: number) {
51    super(nazwa, securityLevel);
52    this.voltage = voltage;
53  }
54
55  aktywuj(): void {
56    console.log(`Electric fence ${this.nazwa} activated with voltage ${this.voltage}V`);
57  }
58
59  dezaktywuj(): void {
60    console.log(`Electric fence ${this.nazwa} deactivated`);
61  }
62
63  increaseVoltage(o: number): void {
64    this.voltage += o;
65    console.log(`Voltage of fence ${this.nazwa} increased to ${this.voltage}V`);
66  }
67}
68
69// Using both approaches
70const skanery = new SkaneryRuchu("T-Rex Zone");
71skanery.aktywuj();
72skanery.testuj();
73
74const ogrodzenie = new ElektroniczneOgrodzenie("Eastern paddock", 4, 10000);
75ogrodzenie.aktywuj();
76ogrodzenie.increaseVoltage(2000);
77console.log(`Fence security level: ${ogrodzenie.pobierzPoziom()}`);

Key differences:

| Feature | Interface | Abstract class | |---------|-----------|----------------| | Implementation | Definition only, no implementation | Can contain method implementations | | Inheritance | Class can implement multiple interfaces | Class can only inherit from one abstract class | | Constructor | No constructor | Can have a constructor | | Runtime code | Interfaces generate no JavaScript code | Abstract classes generate JavaScript code | | Access modifiers | Cannot use modifiers (private, protected) | Can use access modifiers | | Use | Defining a contract | Defining base functionality with partial implementation |

Practical application of interface extension

Let's now see a comprehensive example illustrating how interface extension can be used in the Jurassic Park management system:

1// Base interface for all entities in the park
2interface BazaParkuJurajskiego {
3  id: string;
4  nazwa: string;
5  dataDodania: Date;
6  ostatniaAktualizacja: Date;
7}
8
9// Extension for living creatures
10interface ParkLivingCreatures extends BazaParkuJurajskiego {
11  wiek: number;
12  gender: "male" | "female";
13  statusZdrowia: "excellent" | "good" | "needs attention" | "sick" | "critical";
14  historiaZdrowia: {
15    data: Date;
16    opis: string;
17    procedura?: string;
18  }[];
19}
20
21// Extension for dinosaurs
22interface DinosaurParku extends ParkLivingCreatures {
23  species: string;
24  eraPochodzenia: string;
25  dieta: "herbivore" | "carnivore" | "omnivore";
26  dangerLevel: 1 | 2 | 3 | 4 | 5;
27  lokalizacja: string; // Enclosure ID
28  cechy: {
29    height: number;
30    length: number;
31    waga: number;
32    maxSpeed: number;
33    biteForce?: number; // Only for predators
34  };
35}
36
37// Extension for employees
38interface PracownikParku extends ParkLivingCreatures {
39  firstName: string;
40  nazwisko: string;
41  stanowisko: string;
42  accessLevel: 1 | 2 | 3 | 4 | 5;
43  departments: string[];
44  adres: {
45    ulica: string;
46    miasto: string;
47    kodPocztowy: string;
48    kraj: string;
49  };
50  kontakt: {
51    telefon: string;
52    email: string;
53  };
54}
55
56// Interface for park locations
57interface LokalizacjaParku extends BazaParkuJurajskiego {
58  typ: "enclosure" | "building" | "attraction" | "laboratory" | "public zone";
59  coordinates: {
60    width: number;
61    length: number;
62  };
63  powierzchnia: number; // in square meters
64  capacity: number;
65  accessLevel: 1 | 2 | 3 | 4 | 5;
66  securitySystems: string[]; // List of security system IDs
67  status: "active" | "inactive" | "under maintenance" | "under construction";
68}
69
70// Interface for dinosaur enclosures
71interface WybiegDinosaurs extends LokalizacjaParku {
72  residents: string[]; // List of dinosaur IDs
73  environmentType: "forest" | "savanna" | "swamp" | "mountains" | "coast" | "water";
74  specjalneWymagania?: string[];
75  cechy: {
76    heightOgrodzenia: number;
77    fenceVoltage?: number; // For predators
78    scannersCount: number;
79    liczbaKamer: number;
80  };
81}
82
83// Interface for laboratories
84interface LaboratoriumParku extends LokalizacjaParku {
85  specjalizacja: "genetics" | "behavioral" | "veterinary" | "microbiology";
86  equipment: string[];
87  personel: string[]; // List of employee IDs
88  projektyBadawcze: {
89    id: string;
90    nazwa: string;
91    start: Date;
92    koniec?: Date;
93    status: "planned" | "in progress" | "completed" | "suspended";
94  }[];
95}
96
97// Park management system
98class ParkJurajskiSystem {
99  private dinosaury: Map<string, DinosaurParku> = new Map();
100  private pracownicy: Map<string, PracownikParku> = new Map();
101  private lokalizacje: Map<string, LokalizacjaParku> = new Map();
102  private laboratorium: Map<string, LaboratoriumParku> = new Map();
103  private wybiegi: Map<string, WybiegDinosaurs> = new Map();
104
105  // Methods for dinosaurs
106  dodajDinosaura(dino: DinosaurParku): void {
107    this.dinosaury.set(dino.id, dino);
108    console.log(`Added dinosaur: ${dino.nazwa} (${dino.species})`);
109
110    // Update enclosure
111    if (dino.lokalizacja && this.wybiegi.has(dino.lokalizacja)) {
112      const wybieg = this.wybiegi.get(dino.lokalizacja)!;
113      wybieg.residents.push(dino.id);
114      this.wybiegi.set(wybieg.id, wybieg);
115    }
116  }
117
118  aktualizujStatusZdrowiaDinosaura(id: string, nowyStatus: DinosaurParku["statusZdrowia"], opis: string): void {
119    if (!this.dinosaury.has(id)) {
120      console.error(`Dinosaur with ID ${id} does not exist`);
121      return;
122    }
123
124    const dino = this.dinosaury.get(id)!;
125    const staryStatus = dino.statusZdrowia;
126    dino.statusZdrowia = nowyStatus;
127    dino.ostatniaAktualizacja = new Date();
128
129    // Add entry to health history
130    dino.historiaZdrowia.push({
131      data: new Date(),
132      opis: `Health status changed from "${staryStatus}" to "${nowyStatus}". ${opis}`
133    });
134
135    this.dinosaury.set(id, dino);
136    console.log(`Updated health status of dinosaur ${dino.nazwa} to: ${nowyStatus}`);
137  }
138
139  // Methods for employees
140  dodajPracownika(pracownik: PracownikParku): void {
141    this.pracownicy.set(pracownik.id, pracownik);
142    console.log(`Added employee: ${pracownik.firstName} ${pracownik.nazwisko} (${pracownik.stanowisko})`);
143  }
144
145  // Methods for locations
146  dodajWybieg(wybieg: WybiegDinosaurs): void {
147    this.wybiegi.set(wybieg.id, wybieg);
148    this.lokalizacje.set(wybieg.id, wybieg);
149    console.log(`Added enclosure: ${wybieg.nazwa}`);
150  }
151
152  dodajLaboratorium(lab: LaboratoriumParku): void {
153    this.laboratorium.set(lab.id, lab);
154    this.lokalizacje.set(lab.id, lab);
155    console.log(`Added laboratory: ${lab.nazwa} (${lab.specjalizacja})`);
156  }
157
158  // Reporting methods
159  generujRaportParkuJurajskiego(): string {
160    const raport = [];
161    raport.push("=== JURASSIC PARK STATUS REPORT ===");
162    raport.push(`Report date: ${new Date().toLocaleString()}`);
163    raport.push(`\nGeneral statistics:`);
164    raport.push(`- Number of dinosaurs: ${this.dinosaury.size}`);
165    raport.push(`- Number of employees: ${this.pracownicy.size}`);
166    raport.push(`- Number of locations: ${this.lokalizacje.size}`);
167    raport.push(`  - Enclosures: ${this.wybiegi.size}`);
168    raport.push(`  - Laboratories: ${this.laboratorium.size}`);
169
170    // Dinosaur statistics
171    const statystykiZdrowia = {
172      "excellent": 0,
173      "good": 0,
174      "needs attention": 0,
175      "sick": 0,
176      "critical": 0
177    };
178
179    let predatorsCount = 0;
180
181    for (const dino of this.dinosaury.values()) {
182      statystykiZdrowia[dino.statusZdrowia]++;
183      if (dino.dieta === "carnivore") {
184        predatorsCount++;
185      }
186    }
187
188    raport.push(`\nDinosaur health statistics:`);
189    for (const [status, liczba] of Object.entries(statystykiZdrowia)) {
190      raport.push(`- ${status}: ${liczba}`);
191    }
192
193    raport.push(`Predators: ${predatorsCount}`);
194    raport.push(`Herbivores: ${this.dinosaury.size - predatorsCount}`);
195
196    // Enclosure statistics
197    const wybiegiZeStatusem = {
198      "active": 0,
199      "inactive": 0,
200      "under maintenance": 0,
201      "under construction": 0
202    };
203
204    for (const wybieg of this.wybiegi.values()) {
205      wybiegiZeStatusem[wybieg.status]++;
206    }
207
208    raport.push(`\nEnclosure statistics:`);
209    for (const [status, liczba] of Object.entries(wybiegiZeStatusem)) {
210      raport.push(`- ${status}: ${liczba}`);
211    }
212
213    return raport.join("\n");
214  }
215}
216
217// Example usage
218const park = new ParkJurajskiSystem();
219
220// Adding an enclosure
221park.dodajWybieg({
222  id: "WYB-001",
223  nazwa: "T-Rex Paddock",
224  dataDodania: new Date(2020, 0, 15),
225  ostatniaAktualizacja: new Date(),
226  typ: "enclosure",
227  coordinates: {
228    width: 20.123,
229    length: -75.456
230  },
231  powierzchnia: 50000, // 5 hectares
232  capacity: 2,
233  accessLevel: 5,
234  securitySystems: ["SEC-001", "SEC-002", "SEC-003"],
235  status: "active",
236  residents: [],
237  environmentType: "forest",
238  cechy: {
239    heightOgrodzenia: 8,
240    fenceVoltage: 10000,
241    scannersCount: 24,
242    liczbaKamer: 36
243  }
244});
245
246// Adding a laboratory
247park.dodajLaboratorium({
248  id: "LAB-001",
249  nazwa: "Dr. Wu's Genetics Laboratory",
250  dataDodania: new Date(2018, 5, 10),
251  ostatniaAktualizacja: new Date(),
252  typ: "laboratory",
253  coordinates: {
254    width: 20.124,
255    length: -75.458
256  },
257  powierzchnia: 2000,
258  capacity: 30,
259  accessLevel: 4,
260  securitySystems: ["SEC-101", "SEC-102"],
261  status: "active",
262  specjalizacja: "genetics",
263  equipment: ["DNA sequencer", "Sample isolators", "Cryogenic chamber"],
264  personel: [],
265  projektyBadawcze: [
266    {
267      id: "PROJ-001",
268      nazwa: "Strengthening resistance genes in Triceratops",
269      start: new Date(2022, 3, 15),
270      status: "in progress"
271    }
272  ]
273});
274
275// Adding a dinosaur
276park.dodajDinosaura({
277  id: "DINO-001",
278  nazwa: "Rexy",
279  dataDodania: new Date(2020, 5, 20),
280  ostatniaAktualizacja: new Date(),
281  wiek: 7,
282  gender: "female",
283  statusZdrowia: "good",
284  historiaZdrowia: [
285    {
286      data: new Date(2020, 5, 20),
287      opis: "Initial examination. All parameters within normal range."
288    },
289    {
290      data: new Date(2021, 2, 15),
291      opis: "Routine examination. Slightly elevated triglycerides.",
292      procedura: "Diet change to one richer in Omega-3 fatty acids"
293    }
294  ],
295  species: "Tyrannosaurus Rex",
296  eraPochodzenia: "Late Cretaceous",
297  dieta: "carnivore",
298  dangerLevel: 5,
299  lokalizacja: "WYB-001",
300  cechy: {
301    height: 4.5,
302    length: 12,
303    waga: 7200,
304    maxSpeed: 32,
305    biteForce: 12800
306  }
307});
308
309// Adding an employee
310park.dodajPracownika({
311  id: "EMP-001",
312  nazwa: "Employee",
313  dataDodania: new Date(2019, 1, 10),
314  ostatniaAktualizacja: new Date(),
315  wiek: 42,
316  gender: "male",
317  statusZdrowia: "excellent",
318  historiaZdrowia: [
319    {
320      data: new Date(2022, 1, 5),
321      opis: "Routine periodic examination. All parameters within normal range."
322    }
323  ],
324  firstName: "Owen",
325  nazwisko: "Grady",
326  stanowisko: "Raptor Trainer",
327  accessLevel: 4,
328  departments: ["Behavioral Research", "Animal Care"],
329  adres: {
330    ulica: "Bungalow 12",
331    miasto: "Isla Nublar",
332    kodPocztowy: "00000",
333    kraj: "Costa Rica"
334  },
335  kontakt: {
336    telefon: "+1-555-123-4567",
337    email: "owen.grady@jurassicworld.com"
338  }
339});
340
341// Updating dinosaur health status
342park.aktualizujStatusZdrowiaDinosaura(
343  "DINO-001",
344  "needs attention",
345  "Noticed reduced appetite and slight fever."
346);
347
348// Generating report
349console.log(park.generujRaportParkuJurajskiego());

Summary

Extending interfaces in TypeScript is a powerful technique that allows modeling complex type hierarchies and relationships between them. In the context of Jurassic Park, it enables us to precisely model various entities and systems, from dinosaurs and employees to advanced monitoring and security systems.

| Technique | Use in Jurassic Park | |-----------|----------------------| | Basic interface extension | Hierarchy of creatures from base to specific species | | Extending multiple interfaces | Creating hybrid types, like marine predators | | Generic interface extension | Monitoring systems for different types of data | | Interface declaration merging | Updating security protocols | | Structural compatibility | Uniform treatment of different dinosaur types by security systems |

Dr. Wu summarizes: "Extending interfaces in TypeScript resembles our work on new dinosaur species. We start from a basic structure and extend it with new traits and functionality, creating increasingly specialized and complex entities. This flexibility and ability to reuse existing definitions means we can create cohesive, yet highly diverse systems - key in both genetics and programming."

Go to CodeWorlds