TypeScript Interfaces Cheat Sheet
Programming in TypeScript involves defining and working with different types of data structures and constructs. One such powerful construct in TypeScript is interfaces, which provide a way to define custom types in your code. This cheat sheet will guide you through the essentials of using TypeScript interfaces, ensuring a seamless programming experience.
What are interfaces?
In TypeScript, interfaces play a key role in defining complex types and assisting with type checking. They provide a contract for objects, ensuring they have specific properties with the defined types. An interface doesn't transpile into any JavaScript code, making them a purely TypeScript concept, used for static type-checking.
interface Person {
name: string;
age: number;
}
In the above example, we have an interface Person
with properties name
and age
. This provides a blueprint for any object which claims to be of type Person
.
Interfaces as type
Interfaces can be used to type-check variables. Any variable declared with an interface type must adhere to the structure provided by the interface.
interface Animal {
species: string;
age: number;
}
let dog: Animal = { species: 'Dog', age: 5 }; // Correct usage
let cat: Animal = { species: 'Cat' }; // Error: Property 'age' is missing in type '{ species: string; }'
In this example, Animal
interface is used as a type for the dog
and cat
variables. The cat
variable doesn't follow the Animal
interface structure, resulting in a type error.
Interfaces vs. types
While both interfaces and types can be used to define custom types, interfaces are more extensible because they can be merged and implemented in classes. However, type
is more flexible and can represent primitive types, union types, intersection types, etc., which can't be done with interfaces.
interface A {
x: number;
}
type B = {
y: string;
}
let obj: A & B = { x: 5, y: "hello" };
Here, both A
and B
are custom types, but the way they're declared is different. We're using them together to type-check obj
.
Here is a more in-depth comparison of interfaces vs. types in TypeScript.
Optional properties
Interfaces allow optional properties that might or might not be present in the object. These are denoted by a ?
following the property name.
interface Student {
name: string;
grade?: number;
}
let john: Student = { name: "John" }; // Correct, grade is optional
In this case, john
can be typed with Student
even without providing a grade
because it's an optional property.
Read-only properties
Read-only properties in interfaces are properties that can only be modified when an object is first created. They can't be changed afterwards.
interface Vehicle {
readonly make: string;
model: string;
}
let car: Vehicle = { make: "Toyota", model: "Corolla" };
car.model = "Camry"; // Allowed
car.make = "Honda"; // Error: Cannot assign to 'make' because it is a read-only property.
Here, the make
property of the Vehicle
interface is read-only. Attempting to change its value after object creation results in an error.
Extending interfaces
Interfaces can extend one another, similar to how classes do. This allows us to create new interfaces based on existing ones.
interface Animal {
species: string;
}
interface Dog extends Animal {
barkVolume: number;
}
let myDog: Dog = { species: "Dog", barkVolume: 3 };
In this example, the Dog
interface extends the Animal
interface, and the myDog
object is typed with Dog
.
Interface for function
Interfaces can also define a function type by describing the function's parameter list and return type.
interface Greet {
(name: string, age: number): string;
}
let sayHello: Greet = function(name, age) {
return `Hello ${name}, you are ${age} years old.`;
}
Here, Greet
is an interface for a function with a certain signature. sayHello
is a function that matches this signature.
Interface for array
Interfaces can be used to define the type of array elements.
interface NumberArray {
[index: number]: number;
}
let arr: NumberArray = [1, 2, 3, 4];
In this example, NumberArray
is an interface for an array where the index is a number and the value at that index is also a number. The variable arr
is an example of a NumberArray
.
Remember, mastering interfaces in TypeScript opens up a world of possibilities for structuring and ensuring the integrity of your data in applications. Use this cheat sheet as your quick reference guide while coding!
Implementing Interfaces in Classes
In TypeScript, a class can implement an interface to enforce particular contract (structure). It guarantees that a class has specific properties or methods.
interface Shape {
area(): number;
}
class Circle implements Shape {
constructor(public radius: number) {}
area(): number {
return Math.PI * Math.pow(this.radius, 2);
}
}
let myCircle = new Circle(5);
In this example, the Shape
interface requires a method named area
that returns a number. The Circle
class implements this interface, and so it must contain an area
method that adheres to this contract. Therefore, any instance of Circle
, like myCircle
, will have an area
method.
Indexable Interfaces
Indexable types have an index signature that describes the types we can use to index into the object, along with the corresponding return types when indexing.
interface StringArray {
[index: number]: string;
}
let fruits: StringArray;
fruits = ["Apple", "Banana", "Mango"];
In this example, we have an interface StringArray
that has an index signature. This interface states that when a StringArray
is indexed with a number, it will return a string.
Interface Inheritance
Interfaces can inherit from multiple interfaces, creating a combination of all the interfaces.
interface Shape {
color: string;
}
interface Circle extends Shape {
radius: number;
}
let myCircle: Circle = {color: "red", radius: 5};
Here, Circle
interface is extending the Shape
interface, meaning that it will have all the properties of Shape
plus the ones it defines. So, a Circle
is a Shape
with a radius
.
Hybrid Types
Interfaces can define objects that work as a combination of several types.
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = (function (start: number) { }) as Counter;
counter.interval = 123;
counter.reset = function () { };
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
In this example, Counter
is a complex object with a function signature, a property, and a method. getCounter
is a function that correctly creates a Counter
object.
Working with TypeScript interfaces allows you to write cleaner, more maintainable code that adheres to strict typing rules. By understanding and leveraging the power of interfaces, you can significantly improve your TypeScript coding skills.