JavaScript and TypeScript course Β· Module 6: TypeScript Basics

Interface definitions

11 min read
In this lesson11

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.

What are interfaces in TypeScript?

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.

Basic interface syntax

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// };

Optional properties

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};

Read-only (readonly)

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 property

Function interfaces

Interfaces 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")); // true

Indexable types

Interfaces 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};

Class interfaces

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);

Extending interfaces

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};

Declaration merging for interfaces

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};

Interfaces vs types

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};

Key differences between interface and type:

  1. Extensibility:

    • Interfaces can be extended by multiple declarations with the same name
    • Types cannot be "opened" - once declared, a type cannot be extended
  2. Complex types:

    • Types can directly represent primitive types, unions, intersections
    • Interfaces are more focused on defining the shape of objects
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}

Practical application of interfaces

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);

Summary

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 featureUse in Jurassic Park
Basic definitionData structures for dinosaurs, employees, locations
Optional propertiesAdditional information that may or may not be available
Readonly propertiesData that should not be changed, e.g. genetic IDs
Function interfacesDefinitions of safety procedures and protocols
Indexable typesDynamic databases of dinosaurs and resources
Class interfacesStandards for security and monitoring systems
Extending interfacesInheritance of traits between dinosaur species
Declaration mergingExtending 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."

Code for this lesson: index.ts
1// Interfaces in Jurassic Park
2console.log("TypeScript interfaces\n");
3
4// ===========================================
5// 1. Basic interfaces
6// ===========================================
7console.log("=== BASIC INTERFACES ===");
8
9// A simple interface
10interface Dinosaur {
11  name: string;
12  species: string;
13  age: number;
14  weight: number;
15}
16
17const trex: Dinosaur = {
18  name: "Rexy",
19  species: "Tyrannosaurus Rex",
20  age: 5,
21  weight: 8000
22};
23
24console.log("T-Rex:", trex);
25
26// ===========================================
27// 2. Optional properties
28// ===========================================
29console.log("\n=== OPTIONAL PROPERTIES ===");
30
31interface DinosaurWithOptionals {
32  name: string;
33  species: string;
34  age: number;
35  nickname?: string; // optional
36  medicalNotes?: string; // optional
37}
38
39const blue: DinosaurWithOptionals = {
40  name: "Blue",
41  species: "Velociraptor",
42  age: 3,
43  nickname: "The Beta"
44  // medicalNotes omitted - OK
45};
46
47console.log("Blue:", blue);
48console.log("Has medical notes:", blue.medicalNotes !== undefined);
49
50// ===========================================
51// 3. Readonly properties
52// ===========================================
53console.log("\n=== READONLY PROPERTIES ===");
54
55interface DinosaurWithReadonly {
56  readonly id: string; // cannot be changed
57  readonly dnaSequence: string; // cannot be changed
58  name: string; // can be changed
59  age: number; // can be changed
60}
61
62const dino: DinosaurWithReadonly = {
63  id: "DINO-001",
64  dnaSequence: "ACGT...",
65  name: "Rex",
66  age: 5
67};
68
69// dino.id = "DINO-002"; // Error: Cannot assign to 'id'
70dino.name = "Rexy"; // OK
71dino.age = 6; // OK
72
73console.log("Dinosaur:", dino);
74
75// ===========================================
76// 4. Methods in interfaces
77// ===========================================
78console.log("\n=== METHODS IN INTERFACES ===");
79
80interface DinosaurWithMethods {
81  name: string;
82  species: string;
83  energy: number;
84
85  // Methods
86  roar(): string;
87  eat(amount: number): void;
88  sleep(hours: number): void;
89  getStatus(): string;
90}
91
92class TyrannosaurusRex implements DinosaurWithMethods {
93  name: string;
94  species: string;
95  energy: number;
96
97  constructor(name: string) {
98    this.name = name;
99    this.species = "Tyrannosaurus Rex";
100    this.energy = 100;
101  }
102
103  roar(): string {
104    this.energy -= 5;
105    return `${this.name} roars: ROAAAAAR!`;
106  }
107
108  eat(amount: number): void {
109    this.energy += amount * 2;
110    if (this.energy > 100) this.energy = 100;
111    console.log(`${this.name} ate ${amount}kg. Energy: ${this.energy}`);
112  }
113
114  sleep(hours: number): void {
115    this.energy += hours * 10;
116    if (this.energy > 100) this.energy = 100;
117    console.log(`${this.name} slept ${hours}h. Energy: ${this.energy}`);
118  }
119
120  getStatus(): string {
121    if (this.energy > 70) return "Energetic";
122    if (this.energy > 30) return "Normal";
123    return "Tired";
124  }
125}
126
127const rexy = new TyrannosaurusRex("Rexy");
128console.log(rexy.roar());
129rexy.eat(50);
130console.log("Status:", rexy.getStatus());
131
132// ===========================================
133// 5. Index signatures
134// ===========================================
135console.log("\n=== INDEX SIGNATURES ===");
136
137// Dynamic keys
138interface DinosaurCollection {
139  [id: string]: Dinosaur;
140}
141
142const collection: DinosaurCollection = {
143  "T-001": trex,
144  "V-001": blue
145};
146
147console.log("Collection:", collection);
148console.log("T-001:", collection["T-001"]);
149
150// Mixed properties
151interface PaddockData {
152  id: string;
153  capacity: number;
154  [key: string]: any; // other dynamic properties
155}
156
157const paddock: PaddockData = {
158  id: "P-01",
159  capacity: 10,
160  securityLevel: "high",
161  temperature: 25,
162  humidity: 60
163};
164
165console.log("Paddock:", paddock);
166
167// ===========================================
168// 6. Functions in interfaces
169// ===========================================
170console.log("\n=== FUNCTIONS IN INTERFACES ===");
171
172// Function type
173interface DinosaurFilter {
174  (dino: Dinosaur): boolean;
175}
176
177const carnivoreFilter: DinosaurFilter = (dino) => {
178  return dino.species.includes("saurus") && dino.weight > 1000;
179};
180
181console.log("Is T-Rex carnivore:", carnivoreFilter(trex));
182
183// Interface for functions with properties
184interface DinosaurValidator {
185  (dino: Dinosaur): boolean;
186  errorMessage: string;
187}
188
189const ageValidator: DinosaurValidator = (dino) => {
190  return dino.age >= 0 && dino.age <= 100;
191};
192ageValidator.errorMessage = "Age must be between 0 and 100";
193
194console.log("Validator:", ageValidator(trex));
195console.log("Error message:", ageValidator.errorMessage);
196
197// ===========================================
198// 7. Nested interfaces
199// ===========================================
200console.log("\n=== NESTED INTERFACES ===");
201
202interface Location {
203  latitude: number;
204  longitude: number;
205  altitude: number;
206}
207
208interface Paddock {
209  id: string;
210  name: string;
211  location: Location; // nested interface
212  dimensions: {
213    width: number;
214    length: number;
215    height: number;
216  };
217  dinosaurs: Dinosaur[];
218}
219
220const trexPaddock: Paddock = {
221  id: "P-01",
222  name: "T-Rex Territory",
223  location: {
224    latitude: 22.3964,
225    longitude: -159.5261,
226    altitude: 50
227  },
228  dimensions: {
229    width: 1000,
230    length: 1500,
231    height: 50
232  },
233  dinosaurs: [trex]
234};
235
236console.log("Paddock:", trexPaddock);
237console.log("Location:", trexPaddock.location);
238
239// ===========================================
240// 8. Hybrid types
241// ===========================================
242console.log("\n=== HYBRID TYPES ===");
243
244interface Counter {
245  (start: number): string;
246  interval: number;
247  reset(): void;
248}
249
250function createCounter(): Counter {
251  let count = 0;
252
253  const counter = function(start: number) {
254    count = start;
255    return `Count: ${count}`;
256  } as Counter;
257
258  counter.interval = 1;
259  counter.reset = function() {
260    count = 0;
261  };
262
263  return counter;
264}
265
266const myCounter = createCounter();
267console.log(myCounter(5));
268console.log("Interval:", myCounter.interval);
269myCounter.reset();
270
271// ===========================================
272// 9. Summary
273// ===========================================
274console.log("\n=== SUMMARY ===");
275console.log("Basic interfaces - object structure");
276console.log("Optional properties - ?");
277console.log("Readonly - immutable properties");
278console.log("Methods - functions in interfaces");
279console.log("Index signatures - dynamic keys");
280console.log("Nested interfaces - complex structures");
281
282console.log("\nInterfaces mastered!");

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. How does an interface differ from a type alias in TypeScript?

  2. 2. How do you mark an interface property as optional in TypeScript?

Hands-on tasks in the game

  • Code editor

    Define a Dinosaur interface with fields name: string, species: string, weight?: number and a method roar(): void.

  • Horizontal ordering

    Arrange the elements of a TypeScript interface definition:

  • Click in order

    Arrange the elements of a readonly field definition in an interface:

  • Vertical ordering

    Order interface concepts from simplest to most advanced:

Useful articles