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.
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};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 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);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());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);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);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()}`);| 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 |
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());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."