TypeScript is a statically typed language, which means it checks the types of variables at compile time. However, there are situations where you need to check if an object implements a certain interface at runtime. In this tutorial, we will explore how to achieve runtime interface type checking in TypeScript.
Introduction to Interfaces
In TypeScript, an interface is used to define a contract that must be implemented by any class that implements it. An interface can contain properties, methods, and events, but it does not provide any implementation for these members.
interface A {
member: string;
}
The Problem with Interface Type Checking
When you try to use the instanceof
operator to check if an object implements a certain interface, TypeScript will throw an error. This is because interfaces are not compiled into JavaScript and do not exist at runtime.
var a: any = { member: "foobar" };
if (a instanceof A) {
alert(a.member);
}
This code will result in the following error:
"The name ‘A’ does not exist in the current scope"
Using User-Defined Type Guards
One way to achieve runtime interface type checking is by using user-defined type guards. A type guard is a function that returns a boolean value indicating whether an object matches a certain type.
interface A {
member: string;
}
function instanceOfA(object: any): object is A {
return 'member' in object;
}
var a: any = { member: "foobar" };
if (instanceOfA(a)) {
alert(a.member);
}
In this example, the instanceOfA
function checks if the object
parameter has a member
property. If it does, the function returns true
, indicating that the object implements the A
interface.
Using Discriminators
Another way to achieve runtime interface type checking is by using discriminators. A discriminator is a property that is used to distinguish between different types of objects.
interface A {
discriminator: 'I-AM-A';
member: string;
}
function instanceOfA(object: any): object is A {
return object.discriminator === 'I-AM-A';
}
var a: any = { discriminator: 'I-AM-A', member: "foobar" };
if (instanceOfA(a)) {
alert(a.member);
}
In this example, the discriminator
property is used to check if an object implements the A
interface.
Using Tagged Unions
Tagged unions are a feature in TypeScript that allows you to define a union type with a common discriminator property.
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
type Shape = Square | Rectangle;
function area(s: Shape) {
switch (s.kind) {
case "square": return s.size * s.size;
case "rectangle": return s.width * s.height;
}
}
In this example, the kind
property is used as a discriminator to determine which type of shape an object represents.
Conclusion
Runtime interface type checking in TypeScript can be achieved using user-defined type guards, discriminators, or tagged unions. By using these techniques, you can ensure that your objects conform to certain interfaces and provide more robust and maintainable code.