Welcome back to Jurassic Park! Today, under the watchful eye of Dr. Henry Wu, we will explore a fundamental concept of TypeScript that is just as crucial for code organization as security protocols are for the park's proper operation - interfaces.
Interfaces in TypeScript define contracts in code and describe the structure of objects. They are like detailed protocols that specify what a given object should contain. In the context of Jurassic Park, interfaces can be compared to safety standards and handling protocols for different dinosaur species - each species has its own specific requirements and traits.
We define an interface using the
interface keyword:1interface Dinosaur {
2 id: number;
3 name: string;
4 species: string;
5 age: number;
6 weight: number;
7}
8
9// We create an object that must satisfy the interface requirements
10const rex: Dinosaur = {
11 id: 1,
12 name: "Rex",
13 species: "Tyrannosaurus",
14 age: 7,
15 weight: 8000
16};
17
18// The following code would cause an error because required properties are missing
19// const raptor: Dinosaur = {
20// id: 2,
21// name: "Blue"
22// };Some properties in an interface can be optional, marked by adding a question mark (
?). It's like marking optional handling procedures for individual dinosaurs.1interface DinosaurSpecimen {
2 id: number;
3 name: string;
4 species: string;
5 rfidTag?: string; // Optional RFID tag
6 lastExamination?: Date; // Optional date of last examination
7 notes?: string; // Optional research notes
8}
9
10// Object satisfying the interface, but without all optional properties
11const specimen1: DinosaurSpecimen = {
12 id: 101,
13 name: "Specimen A",
14 species: "Velociraptor"
15};
16
17// Object with some optional properties
18const specimen2: DinosaurSpecimen = {
19 id: 102,
20 name: "Specimen B",
21 species: "Dilophosaurus",
22 rfidTag: "DILO-102",
23 notes: "Shows aggressive behavior in the presence of new objects"
24};Some properties should only be modified when the object is created. In TypeScript we can achieve this using the
readonly modifier. It's like safety procedures that, once established, cannot be changed during normal operations.1interface GeneticCode {
2 readonly id: string;
3 readonly sequence: string;
4 readonly donorSpecies: string;
5 modifications: string[];
6 isolationDate: Date;
7}
8
9// Creating genetic code
10const trexCode: GeneticCode = {
11 id: "GEN-TREX-001",
12 sequence: "ACGTTGCAAGCTA...",
13 donorSpecies: "West African frog",
14 modifications: ["Gap DNA filling", "Aggression gene correction"],
15 isolationDate: new Date("2022-05-15")
16};
17
18// We can add new modifications
19trexCode.modifications.push("Immune resistance enhancement");
20
21// But we cannot change the values of readonly fields
22// trexCode.id = "GEN-TREX-002"; // Error: Cannot assign to 'id' because it is a read-only property
23// trexCode.sequence = "GCTA..."; // Error: Cannot assign to 'sequence' because it is a read-only propertyInterfaces can also define function types, which is useful when describing callbacks or functions passed as parameters. In the context of the park, it's like defining standard procedures for handling different situations.
1// Security check function interface
2interface SecurityCheck {
3 (threatLevel: number, parkZone: string): boolean;
4}
5
6// Implementation of a function conforming to the interface
7const checkAccess: SecurityCheck = function(level, zone) {
8 // Access checking logic
9 if (zone === "T-Rex Enclosure" && level < 5) {
10 return false; // Deny access to T-Rex zone for staff below level 5
11 }
12
13 if (zone.includes("Laboratory") && level < 4) {
14 return false; // Deny access to laboratories for staff below level 4
15 }
16
17 return true; // Access permitted for other cases
18};
19
20// Using the function
21console.log(checkAccess(3, "T-Rex Enclosure")); // false
22console.log(checkAccess(5, "T-Rex Enclosure")); // true
23console.log(checkAccess(3, "Public area")); // trueInterfaces can define indexable types - useful when we have objects with a dynamic number of properties of the same type. In the context of the park, this could be a dinosaur database indexed by their identifiers.
1// Interface for a dinosaur database
2interface DinosaursDatabase {
3 [id: string]: {
4 name: string;
5 species: string;
6 age: number;
7 health: "good" | "needs attention" | "critical";
8 };
9}
10
11// Creating the database
12const database: DinosaursDatabase = {
13 "TREX-001": {
14 name: "Rex",
15 species: "Tyrannosaurus",
16 age: 7,
17 health: "good"
18 },
19 "VELOC-001": {
20 name: "Blue",
21 species: "Velociraptor",
22 age: 4,
23 health: "good"
24 },
25 "TRIC-003": {
26 name: "Trike",
27 species: "Triceratops",
28 age: 10,
29 health: "needs attention"
30 }
31};
32
33// Accessing data
34console.log(database["VELOC-001"].name); // "Blue"
35
36// Adding a new entry
37database["STEGO-002"] = {
38 name: "Spike",
39 species: "Stegosaurus",
40 age: 6,
41 health: "good"
42};Interfaces can also define contracts that classes must implement. It's like operational standards that every department in the park must meet.
1// Interface for security systems
2interface SecuritySystem {
3 name: string;
4 isActive: boolean;
5 securityLevel: number;
6
7 activate(): void;
8 deactivate(): void;
9 checkStatus(): string;
10}
11
12// Class implementing the interface
13class ElectronicFenceSystem implements SecuritySystem {
14 name: string;
15 isActive: boolean;
16 securityLevel: number;
17 voltage: number; // Additional property specific to this class
18
19 constructor(name: string, securityLevel: number, voltage: number) {
20 this.name = name;
21 this.isActive = false; // Initially inactive
22 this.securityLevel = securityLevel;
23 this.voltage = voltage;
24 }
25
26 activate(): void {
27 this.isActive = true;
28 console.log(`System ${this.name} activated. Voltage: ${this.voltage}V`);
29 }
30
31 deactivate(): void {
32 this.isActive = false;
33 console.log(`System ${this.name} deactivated.`);
34 }
35
36 checkStatus(): string {
37 return this.isActive
38 ? `${this.name}: ACTIVE (Level ${this.securityLevel})`
39 : `${this.name}: INACTIVE`;
40 }
41
42 // Method specific to this class
43 increaseVoltage(by: number): void {
44 this.voltage += by;
45 console.log(`Voltage increased to ${this.voltage}V`);
46 }
47}
48
49// Using the class
50const trexFence = new ElectronicFenceSystem("T-Rex Fence", 5, 10000);
51trexFence.activate();
52console.log(trexFence.checkStatus());
53trexFence.increaseVoltage(2000);Interfaces can extend other interfaces, similar to how in biology species share common traits but also have their own unique properties.
1// Basic interface for all animals in the park
2interface Animal {
3 id: number;
4 species: string;
5 age: number;
6 weight: number;
7}
8
9// Interface for dinosaurs extending the Animal interface
10interface Dinosaur extends Animal {
11 era: string; // e.g. "Cretaceous", "Jurassic"
12 isPredator: boolean;
13 mainDiet: string[];
14}
15
16// Interface for predatory dinosaurs extending the Dinosaur interface
17interface PredatoryDinosaur extends Dinosaur {
18 biteForce: number; // in PSI
19 runSpeed: number; // in km/h
20 huntingBehavior: string[];
21}
22
23// Creating an object conforming to the PredatoryDinosaur interface
24const velociraptor: PredatoryDinosaur = {
25 id: 101,
26 species: "Velociraptor",
27 age: 4,
28 weight: 70,
29 era: "Cretaceous",
30 isPredator: true,
31 mainDiet: ["small mammals", "lizards", "other small dinosaurs"],
32 biteForce: 1000,
33 runSpeed: 60,
34 huntingBehavior: ["pack hunting", "ambush", "chase"]
35};In TypeScript it is possible to define the same interface multiple times - the declarations will be merged. This is useful when we want to add new properties to an existing interface.
1// Initial definition of the security protocol
2interface SecurityProtocol {
3 name: string;
4 threatLevel: number;
5 evacuationProcedure: string;
6}
7
8// Extending the protocol with additional properties
9interface SecurityProtocol {
10 responsibleStaff: string[];
11 responseTime: number; // in minutes
12}
13
14// The object must contain all properties from both declarations
15const alphaProtocol: SecurityProtocol = {
16 name: "Protocol Alpha",
17 threatLevel: 3,
18 evacuationProcedure: "Evacuation towards the main control center",
19 responsibleStaff: ["Dr. Wu", "Owen Grady", "Claire Dearing"],
20 responseTime: 15
21};TypeScript also offers the
type keyword for defining types. Although in many cases interfaces and types can be used interchangeably, there are differences between them:1// Definition using interface
2interface EvacuationPlan {
3 route: string[];
4 estimatedTime: number;
5 assemblyPoints: string[];
6}
7
8// Equivalent definition using type
9type EvacuationPlanType = {
10 route: string[];
11 estimatedTime: number;
12 assemblyPoints: string[];
13};
14
15// Both work similarly for basic use
16const planA: EvacuationPlan = {
17 route: ["Operations center", "Main Street", "Evacuation hall"],
18 estimatedTime: 25,
19 assemblyPoints: ["Operations center", "Evacuation hall"]
20};
21
22const planB: EvacuationPlanType = {
23 route: ["Gallimimus Enclosure", "Innovation Center", "Evacuation hall"],
24 estimatedTime: 30,
25 assemblyPoints: ["Innovation Center", "Evacuation hall"]
26};Extensibility:
Complex types:
1// Only possible with types
2type DinosaurID = string | number;
3type EnclosureCoordinates = [number, number, string]; // Tuple
4type DinosaurStatus = "active" | "resting" | "sleeping"; // Union of literals
5
6// More natural with interfaces
7interface Procedure {
8 name: string;
9 steps: string[];
10 executionTime: number;
11 responsibleStaff: string[];
12}Let's look at how we can use interfaces to model the Jurassic Park management system:
1// Basic interfaces
2interface ParkPerson {
3 id: string;
4 firstName: string;
5 lastName: string;
6 accessLevel: 1 | 2 | 3 | 4 | 5;
7 hireDate: Date;
8}
9
10interface Location {
11 id: string;
12 name: string;
13 type: "enclosure" | "laboratory" | "operations center" | "public zone";
14 coordinates: [number, number]; // [latitude, longitude]
15 requiredAccessLevel: 1 | 2 | 3 | 4 | 5;
16}
17
18interface DinosaurSpecies {
19 name: string;
20 geologicalEra: string;
21 type: "herbivore" | "predator" | "omnivore";
22 averageWeight: number;
23 averageAge: number;
24 dangerLevel: 1 | 2 | 3 | 4 | 5;
25 dietRequirements: string[];
26 habitatRequirements: string[];
27}
28
29interface DinosaurSpecimen {
30 id: string;
31 species: string;
32 firstName?: string;
33 age: number;
34 weight: number;
35 gender: "male" | "female";
36 location: string; // Location ID
37 healthStatus: "excellent" | "good" | "needs attention" | "sick" | "critical";
38 lastExamination: Date;
39 rfidTag: string;
40 notes?: string;
41}
42
43// Interfaces for management systems
44interface SpecimenTrackingSystem {
45 getPosition(specimenId: string): [number, number];
46 trackMovement(specimenId: string, trackingTime: number): [number, number][];
47 checkIfInZone(specimenId: string, zoneId: string): boolean;
48 alertWhenOutsideZone(specimenId: string, callback: (specimen: DinosaurSpecimen) => void): void;
49}
50
51interface EmployeeManagementSystem {
52 addEmployee(employee: ParkPerson): void;
53 removeEmployee(id: string): boolean;
54 grantAccess(employeeId: string, level: 1 | 2 | 3 | 4 | 5): boolean;
55 checkPresenceInZone(employeeId: string, zoneId: string): boolean;
56}
57
58// Example implementation
59class ParkManagementSystem {
60 private employees: ParkPerson[] = [];
61 private locations: Location[] = [];
62 private species: DinosaurSpecies[] = [];
63 private specimens: DinosaurSpecimen[] = [];
64
65 // Methods for staff
66 addEmployee(employee: ParkPerson): void {
67 this.employees.push(employee);
68 console.log(`Added employee: ${employee.firstName} ${employee.lastName}`);
69 }
70
71 // Methods for locations
72 addLocation(location: Location): void {
73 this.locations.push(location);
74 console.log(`Added location: ${location.name}`);
75 }
76
77 // Methods for species
78 addSpecies(species: DinosaurSpecies): void {
79 this.species.push(species);
80 console.log(`Added species: ${species.name}`);
81 }
82
83 // Methods for specimens
84 addSpecimen(specimen: DinosaurSpecimen): void {
85 this.specimens.push(specimen);
86 console.log(`Added specimen: ${specimen.id} (${specimen.species})`);
87 }
88
89 // Management methods
90 checkAccess(employeeId: string, locationId: string): boolean {
91 const employee = this.employees.find(p => p.id === employeeId);
92 const location = this.locations.find(l => l.id === locationId);
93
94 if (!employee || !location) return false;
95
96 return employee.accessLevel >= location.requiredAccessLevel;
97 }
98
99 findSpecimensBySpecies(speciesName: string): DinosaurSpecimen[] {
100 return this.specimens.filter(o => o.species === speciesName);
101 }
102
103 findSpecimensInZone(zoneId: string): DinosaurSpecimen[] {
104 return this.specimens.filter(o => o.location === zoneId);
105 }
106
107 generateParkStatusReport(): {
108 employeeCount: number;
109 locationCount: number;
110 speciesCount: number;
111 specimenCount: number;
112 specimenHealthStatus: {
113 excellent: number;
114 good: number;
115 needsAttention: number;
116 sick: number;
117 critical: number;
118 }
119 } {
120 // Analyzing health status of all specimens
121 const healthStatus = {
122 excellent: 0,
123 good: 0,
124 needsAttention: 0,
125 sick: 0,
126 critical: 0
127 };
128
129 this.specimens.forEach(specimen => {
130 if (specimen.healthStatus === "excellent") healthStatus.excellent++;
131 else if (specimen.healthStatus === "good") healthStatus.good++;
132 else if (specimen.healthStatus === "needs attention") healthStatus.needsAttention++;
133 else if (specimen.healthStatus === "sick") healthStatus.sick++;
134 else if (specimen.healthStatus === "critical") healthStatus.critical++;
135 });
136
137 return {
138 employeeCount: this.employees.length,
139 locationCount: this.locations.length,
140 speciesCount: this.species.length,
141 specimenCount: this.specimens.length,
142 specimenHealthStatus: healthStatus
143 };
144 }
145}
146
147// Example usage
148const jurassicPark = new ParkManagementSystem();
149
150// Adding a location
151jurassicPark.addLocation({
152 id: "LOC-001",
153 name: "T-Rex Enclosure",
154 type: "enclosure",
155 coordinates: [23.45, -67.89],
156 requiredAccessLevel: 4
157});
158
159// Adding a species
160jurassicPark.addSpecies({
161 name: "Tyrannosaurus Rex",
162 geologicalEra: "Cretaceous",
163 type: "predator",
164 averageWeight: 7000,
165 averageAge: 30,
166 dangerLevel: 5,
167 dietRequirements: ["large amounts of meat", "calcium supplementation"],
168 habitatRequirements: ["large area", "natural vegetation", "water access"]
169});
170
171// Adding an employee
172jurassicPark.addEmployee({
173 id: "EMP-001",
174 firstName: "Owen",
175 lastName: "Grady",
176 accessLevel: 5,
177 hireDate: new Date("2010-06-15")
178});
179
180// Adding a specimen
181jurassicPark.addSpecimen({
182 id: "DINO-001",
183 species: "Tyrannosaurus Rex",
184 firstName: "Rexy",
185 age: 7,
186 weight: 7500,
187 gender: "female",
188 location: "LOC-001",
189 healthStatus: "good",
190 lastExamination: new Date("2023-03-20"),
191 rfidTag: "RFID-TREX-001"
192});
193
194// Generating a report
195const report = jurassicPark.generateParkStatusReport();
196console.log("Jurassic Park Status Report:");
197console.log(`Number of employees: ${report.employeeCount}`);
198console.log(`Number of locations: ${report.locationCount}`);
199console.log(`Number of species: ${report.speciesCount}`);
200console.log(`Number of specimens: ${report.specimenCount}`);
201console.log("Specimen health status:", report.specimenHealthStatus);Interfaces in TypeScript are a powerful tool for modeling data structures and defining contracts in code. In the context of managing Jurassic Park, they allow us to precisely define what the various systems, procedures and park elements should look like.
| Interface feature | Use in Jurassic Park | |-------------------|----------------------| | Basic definition | Data structures for dinosaurs, employees, locations | | Optional properties | Additional information that may or may not be available | | Readonly properties | Data that should not be changed, e.g. genetic IDs | | Function interfaces | Definitions of safety procedures and protocols | | Indexable types | Dynamic databases of dinosaurs and resources | | Class interfaces | Standards for security and monitoring systems | | Extending interfaces | Inheritance of traits between dinosaur species | | Declaration merging | Extending protocols with additional procedures |
Dr. Wu summarizes: "Interfaces in TypeScript, like our park protocols, ensure that every element of the system works as expected. They allow us to build complex systems with confidence that individual components will work together - which is absolutely crucial when dealing with species that can be dangerous if something goes wrong."